版权声明:本文为博主原创文章,未经博主允许不得转载。 https://cloud.tencent.com/developer/article/1338210
实现分线程
预备概念:
1.进程:一个正在执行的程序
2.线程:由一堆不分叉的CPU指令组成的集合(一个进程中至少包含一个线程)
3.上下文切换:假设一个CPU同时负责两个线程,当线程1时间片结束以后会将线程1的相关信息保存到寄存器中。接下来将时间片分配给线程2,线程2时间片到了以后又将线程2信息保存起来。接下来唤醒线程1的寄存器,将其信息取出,接着上一次执行的命令继续执行,来回切换,直到所有的CPU命令全部完成。
4.多线程的优势和缺点:
一.缺点:
(1)每个线程都会开辟一个空间,如果大量使用多线程会占用大量内存影响性能。
(2)资源竞争。 上锁
(3) 死锁。
二. 优点:
提高用户体验
我们现在的主要目的是实现分线程,目前了解到的有三种方式
1.利用NSObject实现分线程:
开辟一个分线程的代码:
selfperformSelectorInBackground:@selector(getData)withObject:nil;
分线程中的代码:
NSString *path =@"http://c.hiphotos.baidu.com/image/h%3D200/sign=4652d7cac8bf6c81e8372be88c3fb1d7/ d50735fae6cd7b89448109210b2442a7d8330ea6.jpg";
NSURL *url = NSURLURLWithString:path;
NSData *data = NSDatadataWithContentsOfURL:url;
UIImage *image = UIImageimageWithData:data;
selfperformSelectorOnMainThread:@selector(refreshUI:)withObject:image waitUntilDone:NO;
}
此分线程中的代码是获取网络上的一幅图片,这就要设计到刷新UI的问题,刷新UI只能在主线程中,当分线程下载完数据后一定要立刻返回到主线程中,否则就会有延迟。虽然不返回也能实现刷新的效果,这是因为主线程会定时访问分线程,看其是否完成了任务。
主线程刷新UI的代码:
self.myImageView.image = obj;
}
2.利用NSThread实现分线程
开辟分线程的代码:
// 创建一个线程
NSThread *thread = [NSThreadalloc initWithTarget:selfselector:@selector(getData)object:nil];
// 需要手动启动线程
thread start;
利用NSThread这个类来创建,和其他类创建对象是一样的,至于其分线程中的代码是和NSObject中的代码一样的就不太粘贴了。
3.GCD异步下载数据:
GCD:Grand Central Dispatch
利用GCD可以创建队列,然后将任务添加到队列中,这样就产生了一个线程来完成队列中的任务,线程中所有任务结束结束后同样要返回到主线程。
代码:
dispatch_queue_t queue = dispatch_queue_create("com.qianfeng",NULL);
NSLog(@"--%@",NSThreadcurrentThread);
dispatch_async(queue, ^{
NSLog(@"++%@",NSThreadcurrentThread);
NSString *path =@"http://c.hiphotos.baidu.com/image/h%3D200/sign=4652d7cac8bf6c81e8372be88c3fb1d7/
d50735fae6cd7b89448109210b2442a7d8330ea6.jpg";
NSURL *url = NSURLURLWithString:path;
NSData *data = NSDatadataWithContentsOfURL:url;
UIImage *image = UIImageimageWithData:data;
__weak typeof(self) weakSelf =self;
// 回到主线程
dispatch_async(dispatch_get_main_queue(), ^{
// 回到主线程刷新UI,如果不回到主线程刷新UI,刷新会有延迟
weakSelf.myImageView.image = image;
NSLog(@"回到主线程:%@",NSThreadcurrentThread);
});
});
sleep(2);
NSLog(@"====%@",NSThreadcurrentThread);
创建队列中的第二个参数为空说明创建的是一个串行队列(什么是串行队列? 待会说)。代码中的几个nslog语句可以显示程序的执行顺序,并不是执行完分线程,才再去执行主线程的(我们添加分线程是为了提高速度,缩短程序运行时间,提高用户体验)。
说说串行队列:
队列可以分为串行队列和并行队列,联想一下串行电路和并行电路。当队列是串行队列的时候,队列中添加的任务是按顺序执行的,哪怕添加再多的任务也只是一个线程而已。(串行队列中的任务执行顺序只与添加的顺序有关) 与串行队列相对应的是并行队列,并行队列中任务的执行顺序是不确定的,一个并行队列中可能有多个线程,因为只要往队列中添加一个任务就会产生一个线程。
并行队列:
并行队列的创建和串行队列的创建相似,只是第二个参数有所变化。
代码:
dispatch_queue_t queue =dispatch_queue_create("com.1000phone",DISPATCH_QUEUE_CONCURRENT);
切记任务完成后返回主线程。
在并行队列中我们可以利用group来监听并行队列中的全部线程什么时候结束(并行队列中线程的执行顺序是不确定,不好判断什么时候结束,不像并行队列那样,可以在所有任务后再添加一个任务来显示串行队列中的所有任务结束)。
代码:
// 1.创建一个并行队列
dispatch_queue_t queue =dispatch_queue_create("com.1000phone",DISPATCH_QUEUE_CONCURRENT);
// 2.创建一个group
dispatch_group_t group =dispatch_group_create();
// 3.将任务添加到队列里面
// (1)任务一
dispatch_group_async(group, queue, ^{
sleep(3);
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"任务一处理完成");
});
});
// (2)任务二
dispatch_group_async(group, queue, ^{
sleep(1);
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"任务二处理完成");
});
});
});
// 4.通过group监听什么时候所有任务全处理完成
dispatch_group_notify(group,dispatch_get_main_queue(), ^{
NSLog(@"队列中所有任务已经处理完成");
});
以上这么多代码也全是唬人的,实际比前面的队列创建实现分线程也就是多个一个group的创建,和通过group监听。