GCD入门介绍二

一、创建队列和管理队列

1.创建串行Dispatch Queue (serial dispatch queue)

  • 应用的任务需要按特定顺序执行时,就需要使用串行Dispatch Queue,串行queue每次只能执行一个任务。你可以使用串行queue来替代锁,保护共享资源 或可变的数据结构。和锁不一样的是,串行queue确保任务按可预测的顺序执行。只要你异步地提交任务到串行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






你可能感兴趣的:(并发,异步,内存管理,gcd)