GCD入门介绍二
2015-12-02 21:53
435 查看
一、创建队列和管理队列
1.创建串行Dispatch Queue (serial dispatch queue)
应用的任务需要按特定顺序执行时,就需要使用串行Dispatch Queue,串行queue每次只能执行一个任务。你可以使用串行queue来替代锁,保护共享资源 或可变的数据结构。和锁不一样的是,串行queue确保任务按可预测的顺序执行。只要你异步地提交任务到串行queue,就永远不会产生死锁
你必须显式地创建和管理所有你使用的串行queue,应用可以创建任意数量的串行queue,但不要为了同时执行更多任务而创建更多的串行queue。如果你需要并发地执行大量任务,应该把任务提交到全局并发queue
利用dispatch_queue_create函数创建串行queue,两个参数分别是queue名和一组queue属性
并发dispatch queue可以同时并行地执行多个任务,不过并发queue仍然按先进先出的顺序来启动任务。并发queue会在之前的任务完成之前就出列,下一个任务并开始执行。并发queue同时执行的任务数量会根据应用和系统动态变化,各种因素包括:可用核数量、其它进程正在执行的工作数量、其它串行dispatch queue中优先任务的数量等.
系统给每个应用提供三个并发dispatch queue,整个应用内全局共享,三个queue的区别是优先级。你不需要显式地创建这些queue,使用dispatch_get_global_queue函数来获取这三个queue:
3.Dispatch Queue的内存管理
Dispatch Queue和其它dispatch对象(还有dispatch source)都是引用计数的数据类型。当你创建一个串行dispatch queue时,初始引用计数为 1,你可以使用dispatch_retain和dispatch_release函数来增加和减少引用计数。当引用计数到达 0 时,系统会异步地销毁这个queue
对dispatch对象(如dispatch queue)retain和release 是很重要的,确保它们被使用时能够保留在内存中。和OC对象一样,通用的规则是如果使用一个传递过来的queue,你应该在使用前retain,使用完之后release
你不需要retain或release全局dispatch queue,包括全局并发dispatch queue和main dispatch queue
即使你实现的是自动垃圾收集的应用,也需要retain和release创建的dispatch queue和其它dispatch对象。GCD 不支持垃圾收集模型来回收内存
4. 添加任务到queue
要执行一个任务,你需要将它添加到一个适当的dispatch queue,你可以单个或按组来添加,也可以同步或异步地执行一个任务,也。一旦进入到queue,queue会负责尽快地执行你的任务。一般可以用一个block来封装任务内容。
4.1 添加单个任务到queue
1> 异步添加任务
你可以异步或同步地添加一个任务到Queue,尽可能地使用dispatch_async或dispatch_async_f函数异步地调度任务。因为添加任务到Queue中时,无法确定这些代码什么时候能够执行。因此异步地添加block或函数,可以让你立即调度这些代码的执行,然后调用线程可以继续去做其它事情。特别是应用主线程一定要异步地 dispatch 任务,这样才能及时地响应用户事件
2> 同步添加任务
少数时候你可能希望同步地调度任务,以避免竞争条件或其它同步错误。 使用dispatch_sync和dispatch_sync_f函数同步地添加任务到Queue,这两个函数会阻塞当前调用线程,直到相应任务完成执行。注意:绝对不要在任务中调用
dispatch_sync或dispatch_sync_f函数,并同步调度新任务到当前正在执行的 queue。对于串行queue这一点特别重要,因为这样做肯定会导致死锁;而并发queue也应该避免这样做。
3> 代码演示
如果你使用循环执行固定次数的迭代, 并发dispatch queue可能会提高性能。
例如下面的for循环:
queue时,就有可能同时执行多个循环迭代。用dispatch_apply或dispatch_apply_f时你可以指定串行或并发 queue。并发queue允许同时执行多个循环迭代,而串行queue就没太大必要使用了。
下面代码使用dispatch_apply替换了for循环,你传递的block必须包含一个size_t类型的参数,用来标识当前循环迭代。第一次迭代这个参数值为0,最后一次值为count - 1
1.创建串行Dispatch Queue (serial dispatch queue)
你必须显式地创建和管理所有你使用的串行queue,应用可以创建任意数量的串行queue,但不要为了同时执行更多任务而创建更多的串行queue。如果你需要并发地执行大量任务,应该把任务提交到全局并发queue
利用dispatch_queue_create函数创建串行queue,两个参数分别是queue名和一组queue属性
dispatch_queue_t queue; queue = dispatch_queue_create("cn.jingxianli.queue", NULL);2.全局并发Dispatch Queue (concurrent dispatch queue)
并发dispatch queue可以同时并行地执行多个任务,不过并发queue仍然按先进先出的顺序来启动任务。并发queue会在之前的任务完成之前就出列,下一个任务并开始执行。并发queue同时执行的任务数量会根据应用和系统动态变化,各种因素包括:可用核数量、其它进程正在执行的工作数量、其它串行dispatch queue中优先任务的数量等.
系统给每个应用提供三个并发dispatch queue,整个应用内全局共享,三个queue的区别是优先级。你不需要显式地创建这些queue,使用dispatch_get_global_queue函数来获取这三个queue:
// 获取默认优先级的全局并发dispatch queue dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);第一个参数用于指定优先级,分别使用DISPATCH_QUEUE_PRIORITY_HIGH和DISPATCH_QUEUE_PRIORITY_LOW两个常量来获取高和低优先级的两个queue;第二个参数目前未使用到,默认0即可。
3.Dispatch Queue的内存管理
Dispatch Queue和其它dispatch对象(还有dispatch source)都是引用计数的数据类型。当你创建一个串行dispatch queue时,初始引用计数为 1,你可以使用dispatch_retain和dispatch_release函数来增加和减少引用计数。当引用计数到达 0 时,系统会异步地销毁这个queue
对dispatch对象(如dispatch queue)retain和release 是很重要的,确保它们被使用时能够保留在内存中。和OC对象一样,通用的规则是如果使用一个传递过来的queue,你应该在使用前retain,使用完之后release
你不需要retain或release全局dispatch queue,包括全局并发dispatch queue和main dispatch queue
即使你实现的是自动垃圾收集的应用,也需要retain和release创建的dispatch queue和其它dispatch对象。GCD 不支持垃圾收集模型来回收内存
4. 添加任务到queue
要执行一个任务,你需要将它添加到一个适当的dispatch queue,你可以单个或按组来添加,也可以同步或异步地执行一个任务,也。一旦进入到queue,queue会负责尽快地执行你的任务。一般可以用一个block来封装任务内容。
4.1 添加单个任务到queue
1> 异步添加任务
你可以异步或同步地添加一个任务到Queue,尽可能地使用dispatch_async或dispatch_async_f函数异步地调度任务。因为添加任务到Queue中时,无法确定这些代码什么时候能够执行。因此异步地添加block或函数,可以让你立即调度这些代码的执行,然后调用线程可以继续去做其它事情。特别是应用主线程一定要异步地 dispatch 任务,这样才能及时地响应用户事件
2> 同步添加任务
少数时候你可能希望同步地调度任务,以避免竞争条件或其它同步错误。 使用dispatch_sync和dispatch_sync_f函数同步地添加任务到Queue,这两个函数会阻塞当前调用线程,直到相应任务完成执行。注意:绝对不要在任务中调用
dispatch_sync或dispatch_sync_f函数,并同步调度新任务到当前正在执行的 queue。对于串行queue这一点特别重要,因为这样做肯定会导致死锁;而并发queue也应该避免这样做。
3> 代码演示
// 调用前,查看下当前线程 NSLog(@"当前调用线程:%@", [NSThread currentThread]); // 创建一个串行queue dispatch_queue_t queue = dispatch_queue_create("cn.jingxianli.queue", NULL); dispatch_async(queue, ^{ NSLog(@"开启了一个异步任务,当前线程:%@", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"开启了一个同步任务,当前线程:%@", [NSThread currentThread]); });打印信息:
2015-12-02 21:29:49.298 test001[3483:60b] 当前调用线程:<NSThread: 0x8c76ae0>{name = (null), num = 1} 2015-12-02 21:30:34.673 test001[3483:3107] 开启了一个异步任务,当前线程:<NSThread: 0x8e75410>{name = (null), num = 2} 2015-12-02 21:30:35.868 test001[3483:60b] 开启了一个同步任务,当前线程:<NSThread: 0x8c76ae0>{name = (null), num = 1}4.2 并发地执行循环迭代
如果你使用循环执行固定次数的迭代, 并发dispatch queue可能会提高性能。
例如下面的for循环:
int count = 10; for (int i=0; i<count; i++) { NSLog(@"%d",i); }1> 如果每次迭代执行的任务与其它迭代独立无关,而且循环迭代执行顺序也无关紧要的话,可以调用dispatch_apply或dispatch_apply_f函数来替换循环。这两个函数为每次循环迭代将指定的block或函数提交到queue。当dispatch到并发
queue时,就有可能同时执行多个循环迭代。用dispatch_apply或dispatch_apply_f时你可以指定串行或并发 queue。并发queue允许同时执行多个循环迭代,而串行queue就没太大必要使用了。
下面代码使用dispatch_apply替换了for循环,你传递的block必须包含一个size_t类型的参数,用来标识当前循环迭代。第一次迭代这个参数值为0,最后一次值为count - 1
//获得全局并发queue dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); size_t count = 10; dispatch_apply(count, queue, ^(size_t i) { NSLog(@"%zd",i); });打印信息:
2015-12-02 21:51:26.693 test001[3559:60b] 1 2015-12-02 21:51:26.693 test001[3559:3503] 3 2015-12-02 21:51:26.693 test001[3559:3403] 2 2015-12-02 21:51:26.693 test001[3559:1303] 0 2015-12-02 21:51:26.695 test001[3559:60b] 4 2015-12-02 21:51:26.696 test001[3559:60b] 8 2015-12-02 21:51:26.696 test001[3559:1303] 7 2015-12-02 21:51:26.695 test001[3559:3503] 5 2015-12-02 21:51:26.696 test001[3559:3403] 6 2015-12-02 21:51:26.697 test001[3559:60b] 9
相关文章推荐
- ruby实现的一个异步文件下载HttpServer实例
- C#异步绑定数据实现方法
- Lua的内存管理浅析
- 科学知识:同步、异步、阻塞和非阻塞区别
- 探讨Ajax中同步与异步之间的区别
- C#中异步回调函数用法实例
- 探究在C++程序并发时保护共享数据的问题
- C#实现异步GET的方法
- C#异步执行任务的方法
- 深入理解JavaScript编程中的同步与异步机制
- 跟我学习JScript的Bug与内存管理
- Nodejs实战心得之eventproxy模块控制并发
- Jquery异步提交表单代码分享
- JQuery异步获取返回值中文乱码的解决方法
- 跟我学习javascript的垃圾回收机制与内存管理
- Node.js 的异步 IO 性能探讨
- Ajax异步(请求)提交类 支持跨域
- jQuery中的ajax async同步和异步详解
- Ajax异步请求JSon数据(图文详解)
- 使用kendynet构建异步redis访问服务