iOS 多线程编程之GCD
来源:互联网 发布:java中tcp和udp的区别 编辑:程序博客网 时间:2024/05/18 19:46
三种多线程编程技术简介
iOS的三种多线程编程技术对比(这三种编程方式从上到下,抽象度层次是从低到高的,抽象度越高的使用越简单,也是Apple最推荐使用的。):
- NSThread
- 优点:最轻量级
- 缺点:需要自己管理线程的生命周期,线程同步。线程同步对数据的加锁会有一定的系统开销
- Cocoa NSOperation
- 优点:不需要关心线程管理,数据同步的事情,可以把精力放在自己需要执行的操作上。
- GCD
- 在iOS4.0开始之后才能使用。GCD是一个替代诸如NSThread, NSOperationQueue, NSInvocationOperation等技术的很高效和强大的技术
NSThread
NSThread已经有文章介绍得很详细,请看这里《iOS多线程编程之NSThread的使用》
NSOperation和NSOperationQueue
NSOperation和NSOperationQueue已经有文章介绍得很详细,请看这里《iOS多线程编程之NSOperation和NSOperationQueue的使用》
GCD
GCD全称Grand Central Dispatch,是苹果为多核的并行运算提出的解决方案,所以会自动合理地利用更多的CPU内核(比如双核、四核),最重要的是它会自动管理线程的生命周期(创建线程、调度任务、销毁线程),完全不需要我们管理,我们只需要告诉干什么就行。同时它使用的也是 c语言,不过由于使用了 Block(Swift里叫做闭包),使得使用起来更加方便,而且灵活。
1. 工作原理
GCD的工作原理是:让程序平行排队的特定任务,根据可用的处理资源,安排他们在任何可用的处理器核心上执行任务。一个任务可以是一个函数(function)或者是一个block。 GCD的底层依然是用线程实现,不过这样可以让程序员不用关注实现的细节。
GCD中的FIFO队列称为dispatch queue,它可以保证先进来的任务先得到执行。
2.任务和队列
在 GCD 中,加入了两个非常重要的概念: 任务 和 队列。
- 任务:即操作,你想要干什么,说白了就是一段代码,在 GCD 中就是一个 Block,所以添加任务十分方便。任务有两种执行方式: 同步执行 和 异步执行:
- 同步(sync) 操作,它会阻塞当前线程并等待 Block 中的任务执行完毕,然后当前线程才会继续往下运行。
- 异步(async)操作,当前线程会直接往下执行,它不会阻塞当前线程。它们主要区别在于会不会阻塞当前线程,直到 Block 中的任务执行完毕。
- 队列:用于存放任务。一共有两种队列, 串行队列 和 并行队列:
- 串行:放到串行队列的任务,GCD 会 FIFO(先进先出) 地取出来一个,执行一个,然后取下一个,这样一个一个的执行。
- 并行:放到并行队列的任务,GCD 也会 FIFO的取出来,但不同的是,它取出来一个就会放到别的线程,然后再取出来一个又放到另一个的线程。这样由于取的动作很快,忽略不计,看起来,所有的任务都是一起执行的。不过需要注意,GCD 会根据系统资源控制并行的数量,所以如果任务很多,它并不会让所有任务同时执行。
3.分类
dispatch queue分为下面两种:
- Serial
又称为private dispatch queues,线性执行的线程队列,遵循FIFO(First In First Out)原则。Serial queue通常用于同步访问特定的资源或数据。当你创建多个Serial queue时,虽然它们各自是同步执行的,但Serial queue与Serial queue之间是并发执行的。
dispatch_queue_t serialQueue = dispatch_queue_create("com.mark.serialQueue", NULL);dispatch_async(serialQueue, ^{ NSLog(@"block on serialQueue");});dispatch_release(serialQueue);
- Concurrent
又称为global dispatch queue,可以并发地执行多个任务,并发执行的处理数取决于当前状态,执行完成的顺序是随机的。
dispatch_queue_t concurrentQueue = dispatch_queue_create("com.mark.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);dispatch_async(concurrentQueue, ^{ NSLog(@"block on concurrentQueue");});dispatch_release(concurrentQueue);
系统的dispatch queue:
Main dispatch queue
它是全局可用的serial queue,在程序的RunLoop中执行任务。Global Dispatch Queue
系统中所有应用程序共用的全局队列(Concurrent Queue), 一般不必创建新的Dispatch Queue,使用此Queue就可以了。有四个优先级:
DISPATCH_QUEUE_PRIORITY_HIGH
DISPATCH_QUEUE_PRIORITY_DEFAULT
DISPATCH_QUEUE_PRIORITY_LOW
DISPATCH_QUEUE_PRIORITY_BACKGROUND
4.实现
dispath_get_global_queue
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 耗时的操作,例如下载网络图片 dispatch_async(dispatch_get_main_queue(), ^{ // 主线程操作,例如更新界面 }); });
是不是代码比NSThread NSOperation简洁很多,而且GCD会自动根据任务在多核处理器上分配资源,优化程序。
系统给每一个应用程序提供了三个concurrent dispatch queues。这三个并发调度队列是全局的,它们只有优先级的不同。因为是全局的,我们不需要去创建。我们只需要通过使用函数dispath_get_global_queue去得到队列,如下:
dispatch_queue_t globalQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
这里线程的优先级是DISPATCH_QUEUE_PRIORITY_DEFAULT,若要改变线程优先级,用dispatch_set_target_queue:
// 改变serialQueue(Default Priority)优先级为Background Prioritydispatch_queue_t serialQueue = dispatch_queue_create("com.mark.serialQueue", NULL);dispatch_queue_t globalDispatchQueueBackground = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);dispatch_set_target_queue(serialQueue, globalDispatchQueueBackground);
dispatch_get_main_queue
上面的例子中也用到了系统默认就有一个串行队列main_queue,它运行在程序的RunLopp中。
dispatch_queue_t mainQ = dispatch_get_main_queue();
虽然dispatch queue是引用计数的对象,但是dispatch_get_global_queue和dispatch_get_main_queue都是全局的队列,不用retain或release。
dispatch_group_async
dispatch_group_async可以实现监听一组任务是否完成,完成后得到通知执行其他的操作。这个方法很有用,比如你执行三个下载任务,当三个任务都下载完成后你才通知界面说完成的了。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, queue, ^{ [NSThread sleepForTimeInterval:1]; NSLog(@"group1"); }); dispatch_group_async(group, queue, ^{ [NSThread sleepForTimeInterval:2]; NSLog(@"group2"); }); dispatch_group_async(group, queue, ^{ [NSThread sleepForTimeInterval:3]; NSLog(@"group3"); }); dispatch_group_notify(group, dispatch_get_main_queue(), ^{ NSLog(@"updateUi"); }); dispatch_release(group);
dispatch_group_async是异步的方法,运行后可以看到打印结果:
2015-11-25 17:47:09.625 NSThreadDemo[47595:12836120] group1
2015-11-25 17:47:10.624 NSThreadDemo[47595:12836122] group2
2015-11-25 17:47:11.620 NSThreadDemo[47595:12836651] group3
2015-11-25 17:47:11.620 NSThreadDemo[47595:12831653] updateUi
每个一秒打印一个,当第三个任务执行后,upadteUi被打印。
dispatch_barrier_async
dispatch_barrier_async是在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行
dispatch_queue_t queue = dispatch_queue_create("gcdtest.rongfzh.yc", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:2]; NSLog(@"dispatch_async1"); }); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:4]; NSLog(@"dispatch_async2"); }); dispatch_barrier_async(queue, ^{ NSLog(@"dispatch_barrier_async"); [NSThread sleepForTimeInterval:4]; }); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:1]; NSLog(@"dispatch_async3"); });
执行后打印结果:
2015-11-25 17:47:58.256 NSThreadDemo[47632:12844832] dispatch_async1
2015-11-25 17:48:00.259 NSThreadDemo[47632:12844831] dispatch_async2
2015-11-25 17:48:00.259 NSThreadDemo[47632:12844831] dispatch_barrier_async
2015-11-25 17:48:05.264 NSThreadDemo[47632:12844831] dispatch_async3
dispatch_apply
执行某个代码片段N次。
dispatch_apply(5, globalQ, ^(size_t index) { // 执行5次});
dispatch_after
这个函数可以使线程延时执行:
// 2秒后将指定的Block增加到指定的Dispatch Queue中double delayInSeconds = 2.0;dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ NSLog(@"Waitted at least 2 seconds");});
线程队列的挂起与执行
// 挂起队列dispatch_suspend(queue);// 恢复队列执行dispatch_resume(queue);
dispatch_once
只执行一次制定处理的API
static dispatch_once_t pred;dispatch_once(&pred, ^{ // 初始化,这里多用于单例的模式});
- iOS多线程编程之GCD
- iOS多线程编程之GCD
- iOS 多线程编程之GCD
- iOS多线程编程之GCD
- iOS-多线程编程之GCD
- iOS多线程编程之GCD介绍
- iOS多线程编程之GCD的使用
- iOS多线程编程--GCD
- iOS多线程编程GCD
- iOS 多线程之----------GCD
- IOS多线程之GCD
- IOS 多线程之GCD
- iOS多线程之GCD
- ios多线程之GCD
- iOS多线程之GCD
- ios多线程之GCD
- IOS多线程之GCD
- IOS多线程之GCD
- [终端工具] 方便实用的下拉式(Top-Down)终端 --- Guake Terminal
- java正则表达式(HTML提取)
- Mycat在使用注解ShareJoin遇到的错误
- Android控件之AutoCompleteTextView
- 差分gps系统搭建
- iOS 多线程编程之GCD
- Maven中国镜像
- 布局中使用权重对齐问题
- iOS学习笔记--04 NSUserDefaults
- iOS开发笔记-判断输入的是否是汉字
- ThreadPoolExecutor使用和思考(上)-线程池大小设置与BlockingQueue的三种实现区别
- 微信去除 防欺诈或盗号请不要输入qq密码 的方法
- oracle启动和关闭数据库
- 项目名称上有红叉