标签:
上一章我们讨论了iOS中的网络部分的进程线程多线程的相关知识,并且初步了解了NSThread的操作。但是NSThread是有问题的。比如在某个实例,我们需要在当tableView 中显示许多的cell,而cell上是来自网络加载的图片数据。那么我们需要在代理方法中调用cell的时候对imageView添加图片。传统的UIImageView的setImage方法是在主线程中执行的。图片较少的情况下是看不出什么卡顿的效果。但是如果图片的数量很多的情况下如果不使用cell复用,xib下显示100张图片就会卡的要死。
使用NSThread方法
NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(loadImageWithUrl:) object:app.imageUrl];
-(void)loadImageWithUrl:(NSString*)urlStr{
NSLog(@"loadImageWithUrl:%@",[NSThread currentThread]);
//同步下载一个图片
NSURL *url = [NSURL URLWithString:urlStr];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
//刷一下UI
self.iconImageView.image = image;
}
依然看不出什么性能上的改变。
我们修改代码,将刷新UI的代码修改为:
[self.iconImageView performSelectorInMainThread:@selector(setImage:)withObject:image waitUntilDone:nil];
即在主线程中运行。会发现程序更卡。
那么该怎么做?
GCD。
在这里修改代码,setApp:(AppModel*)model
{
//获取队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0);
//派遣线程任务
dispatch_async(queue,^{
[self loadImageViewWithUrl:model.imageUrl];
});
}
这样效率大大提升。
接下来详细介绍一下GCD。
GCD,全称:Grand Central Dispatch 多线程优化技术,定义了一套底层api,基于c语言开发的多线程机制,它提供了新的模式,编写并发执行的程序。
GCD的特点:
1。允许将一个程序切分为单一的任务,然后提交到工作队列中并发或者串行地执行。
2.为多核的并行计算提出了解决方案,自动合理利用cpu内核。
3.自动管理线程的生命周期 包括创建线程,调度任务,销毁线程,派遣任务,完全不用为我们管理。
4.基本上一些任务的代码是通过block。
概念2:Queue队列
GCD使用了队列的概念。解决了NSThread难以管理的问题
特点:1.顺序执行先进先出。
2.管理多线程,管理并发任务 设置主线程。
3.GCD是任务的队列 而不是线程的队列。
概念3:任务 任务在GCD中 就是在block中设置的执行代码。
有两种执行方式,1)同步执行:只要是同步任务 都会在当前线程,不会另外开启线程。2)异步执行:只要是异步任务 都会开启新线程,在新线程中执行。
概念4:队列分类
1)串行队列 依次完成任务
2)并行队列 在同一时刻并发执行多个任务。
此外还涉及到 主队列,全局队列,自创建队列等。
GCD主要涉及到三种队列形式,自定义队列 全局队列 主队列等。
程序一:自定义队列
-(void)viewDidLoad
{
[super viewDidLoad];
[self createMyQueues];
}
同步队列
-(void)createQueue { dispatch_queue_t queue = dispatch_queue_create("MyQueue", NULL); //同步队列 dispatch_sync(queue, ^{ [self work]; [self eat]; }); } #pragma mark - 任务 -(void)eat { int i = 0; while (i ++<10) { NSLog(@"吃%d",i); [NSThread sleepForTimeInterval:1.0]; } } -(void)work { int i = 0; while (i++ <10) { NSLog(@"我是%d",i); [NSThread sleepForTimeInterval:1.0]; } }
执行结果为:
2015-09-16 21:12:00.636 gcd复习[5790:304856] 我是1 2015-09-16 21:12:01.637 gcd复习[5790:304856] 我是2 2015-09-16 21:12:02.640 gcd复习[5790:304856] 我是3 2015-09-16 21:12:03.640 gcd复习[5790:304856] 我是4 2015-09-16 21:12:04.641 gcd复习[5790:304856] 我是5 2015-09-16 21:12:05.644 gcd复习[5790:304856] 我是6 2015-09-16 21:12:06.649 gcd复习[5790:304856] 我是7 2015-09-16 21:12:07.652 gcd复习[5790:304856] 我是8 2015-09-16 21:12:08.654 gcd复习[5790:304856] 我是9 2015-09-16 21:12:09.656 gcd复习[5790:304856] 我是10 2015-09-16 21:12:10.660 gcd复习[5790:304856] 吃1 2015-09-16 21:12:11.661 gcd复习[5790:304856] 吃2 2015-09-16 21:12:12.664 gcd复习[5790:304856] 吃3 2015-09-16 21:12:13.666 gcd复习[5790:304856] 吃4 2015-09-16 21:12:14.670 gcd复习[5790:304856] 吃5 2015-09-16 21:12:15.672 gcd复习[5790:304856] 吃6 2015-09-16 21:12:16.673 gcd复习[5790:304856] 吃7 2015-09-16 21:12:17.674 gcd复习[5790:304856] 吃8 2015-09-16 21:12:18.675 gcd复习[5790:304856] 吃9 2015-09-16 21:12:19.676 gcd复习[5790:304856] 吃10
可以看出 两个任务是串行执行,即同步。此时需要注意的是,这里的线程是主线程,并没有新建任何线程。
异步队列:
dispatch_async(queue, ^{
[self work];
[self eat];
});
执行结果:
2015-09-16 21:18:09.586 gcd复习[5905:308576] 我是9 2015-09-16 21:18:10.588 gcd复习[5905:308576] <NSThread: 0x7fd7a8423070>{number = 1, name = main} 2015-09-16 21:18:10.588 gcd复习[5905:308576] 我是10 2015-09-16 21:18:11.593 gcd复习[5905:308576] <NSThread: 0x7fd7a8423070>{number = 1, name = main} 2015-09-16 21:18:11.593 gcd复习[5905:308576] 吃1 2015-09-16 21:18:12.596 gcd复习[5905:308576] <NSThread: 0x7fd7a8423070>{number = 1, name = main} 2015-09-16 21:18:12.596 gcd复习[5905:308576] 吃2 2015-09-16 21:18:13.599 gcd复习[5905:308576] <NSThread: 0x7fd7a8423070>{number = 1, name = main} 2015-09-16 21:18:13.599 gcd复习[5905:308576] 吃3 2015-09-16 21:18:14.600 gcd复习[5905:308576] <NSThread: 0x7fd7a8423070>{number = 1, name = main} 2015-09-16 21:18:14.600 gcd复习[5905:308576] 吃4
从以上执行结果可以看出 当前异步队列下 开辟了一个新的线程,且两个任务串行执行在该子线程中。
需要注意的是,异步队列下,程序会在两个线程中执行。
以以下代码为例
dispatch_async(queue, ^{ [self print1]; // [self print2]; }); // dispatch_async(queue1, ^{ // [self print1]; [self print2]; });
当前的异步队列下会创建一个新的线程,所以当前的print1 print2函数会并发执行。
如果我想让程序在线程任务执行完毕之后执行另外的一件事情,那么需要用到队列组。
//创建队列组 dispatch_group_t group = dispatch_group_create(); //将事件统一到组中。 dispatch_group_async(group, queue1, ^{ NSLog(@"%@",[NSThread currentThread]); [self print1]; }); dispatch_group_async(group, queue2, ^{ NSLog(@"%@",[NSThread currentThread]); [self print2]; }); dispatch_group_async(group, queue3, ^{ NSLog(@"%@",[NSThread currentThread]); [self print3]; }); dispatch_group_async(group, queue4, ^{ NSLog(@"%@",[NSThread currentThread]); [self print4]; });
#pragma mark - 多队列任务 -(void)print1 { for (int i = 0; i < 10; i++) { NSLog(@"第1个任务执行,%d步",i); [NSThread sleepForTimeInterval:1.0]; } } -(void)print2 { for (int i = 0; i < 10; i++) { NSLog(@"第2个任务执行,%d步",i); [NSThread sleepForTimeInterval:1.0]; } } -(void)print3 { for (int i = 0; i < 10; i++) { NSLog(@"第3个任务执行,%d步",i); [NSThread sleepForTimeInterval:1.0]; } } -(void)print4 { for (int i = 0; i < 10; i++) { NSLog(@"第4个任务执行,%d步",i); [NSThread sleepForTimeInterval:1.0]; } }
dispatch_group_notify(group, queue5, ^{ NSLog(@"%d",[NSThread isMultiThreaded]); NSLog(@"--%@",[NSThread currentThread]); NSLog(@"%@",@"完成了"); });
在所有任务执行完成之后该方法会执行。但是并不会创建新线程。
实例2 获取全局队列
特点:
1.可以同时运行多个任务,每个任务的启动时间是按照加入queue的顺序执行的
2.我们不能自己创建并调度全局队列,只有三个可用的线程
-(void)getGlobalQueue { dispatch_group_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); dispatch_async(queue, ^{ NSLog(@"queue:%@",[NSThread currentThread]); [self print1]; //[self print2]; }); dispatch_async(queue, ^{ NSLog(@"queue:%@",[NSThread currentThread]); [self print3]; //[self print4]; }); }
运行结果如下
2015-09-16 22:39:14.680 gcd复习[6738:347874] <NSThread: 0x7fa90be12f90>{number = 1, name = main} 2015-09-16 22:39:14.681 gcd复习[6738:347959] queue:<NSThread: 0x7fa90be22b40>{number = 2, name = (null)} 2015-09-16 22:39:14.681 gcd复习[6738:347959] 第3个任务执行,0步 2015-09-16 22:39:14.682 gcd复习[6738:347960] queue:<NSThread: 0x7fa90bd24300>{number = 3, name = (null)} 2015-09-16 22:39:14.682 gcd复习[6738:347960] 第1个任务执行,0步 2015-09-16 22:39:15.682 gcd复习[6738:347959] 第3个任务执行,1步 2015-09-16 22:39:15.683 gcd复习[6738:347960] 第1个任务执行,1步 2015-09-16 22:39:16.684 gcd复习[6738:347960] 第1个任务执行,2步 2015-09-16 22:39:16.684 gcd复习[6738:347959] 第3个任务执行,2步 2015-09-16 22:39:17.685 gcd复习[6738:347959] 第3个任务执行,3步 2015-09-16 22:39:17.685 gcd复习[6738:347960] 第1个任务执行,3步 2015-09-16 22:39:18.688 gcd复习[6738:347960] 第1个任务执行,4步 2015-09-16 22:39:18.688 gcd复习[6738:347959] 第3个任务执行,4步 2015-09-16 22:39:19.689 gcd复习[6738:347959] 第3个任务执行,5步 2015-09-16 22:39:19.689 gcd复习[6738:347960] 第1个任务执行,5步 2015-09-16 22:39:20.690 gcd复习[6738:347959] 第3个任务执行,6步 2015-09-16 22:39:20.690 gcd复习[6738:347960] 第1个任务执行,6步 2015-09-16 22:39:21.692 gcd复习[6738:347960] 第1个任务执行,7步 2015-09-16 22:39:21.692 gcd复习[6738:347959] 第3个任务执行,7步 2015-09-16 22:39:22.693 gcd复习[6738:347960] 第1个任务执行,8步 2015-09-16 22:39:22.693 gcd复习[6738:347959] 第3个任务执行,8步 2015-09-16 22:39:23.698 gcd复习[6738:347959] 第3个任务执行,9步 2015-09-16 22:39:23.698 gcd复习[6738:347960] 第1个任务执行,9步
从以上可以看出 异步队列创建了两个新的线程 并且并行执行这两个任务。
-(void)getGlobalQueue { dispatch_group_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); dispatch_async(queue, ^{ NSLog(@"queue:%@",[NSThread currentThread]); [self print1]; //[self print2]; }); dispatch_sync(queue, ^{ NSLog(@"queue--:%@",[NSThread currentThread]); [self print3]; //[self print4]; }); }
如以上写法 则在同步方法中不会创建新的线程。任务并行执行。
实例3:主队列
//获取主队列 -(void)getMainQueue { dispatch_async(dispatch_get_main_queue(), ^{ for (int i = 0; i <10; i ++) { NSLog(@"%@",[NSThread currentThread]); NSLog(@"multi:%d",[NSThread isMultiThreaded]); NSLog(@"main:%d",[NSThread isMultiThreaded]); sleep(1.0); } }); }
以上就是GCD今天的讨论内容了。
标签:
原文地址:http://www.cnblogs.com/mosuyanxue/p/4814844.html