GCD 的简单理解

转自:http://blog.csdn.net/jasonblog/article/details/7816999   

GCD,全称Grand Central Dispath,是苹果开发的一种支持并行操作的机制。它的主要部件是一个FIFO队列和一个线程池,前者用来添加任务,后者用来执行任务。

     GCD中的FIFO队列称为dispatch queue,它可以保证先进来的任务先得到执行(但不保证一定先执行结束)。

     通过与线程池的配合,dispatch queue分为下面两种:

  •      Serial Dispatch Queue -- 线程池只提供一个线程用来执行任务,所以后一个任务必须等到前一个任务执行结束才能开始。
  •      Concurrent Dispatch Queue -- 线程池提供多个线程来执行任务,所以可以按序启动多个任务并发执行。

1. Basic Management

     我们可以通过dispatch_queue_cretae来创建队列,然后用dispatch_release释放。比如下面两段代码分别创建串行队列和并行队列:

  1. dispatch_queue_t serialQ = dispatch_queue_create("eg.gcd.SerialQueue", DISPATCH_QUEUE_SERIAL);  
  2. dispatch_async(serialQ, ^{  
  3.     // Code here   
  4. });  
  5. dispatch_release(serialQ);  
  6.   
  7. dispatch_queue_t concurrentQ = dispatch_queue_create("eg.gcd.ConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);  
  8. dispatch_async(concurrentQ, ^{  
  9.     // Code here   
  10. });  
  11. dispatch_release(concurrentQ);  
dispatch_queue_t serialQ = dispatch_queue_create("eg.gcd.SerialQueue", DISPATCH_QUEUE_SERIAL);
dispatch_async(serialQ, ^{
    // Code here
});
dispatch_release(serialQ);

dispatch_queue_t concurrentQ = dispatch_queue_create("eg.gcd.ConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(concurrentQ, ^{
    // Code here
});
dispatch_release(concurrentQ);

     而系统默认就有一个串行队列main_queue和并行队列global_queue:

  1. dispatch_queue_t globalQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);  
  2. dispatch_queue_t mainQ = dispatch_get_main_queue();  
dispatch_queue_t globalQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_queue_t mainQ = dispatch_get_main_queue();

     通常,我们可以在global_queue中做一些long-running的任务,完成后在main_queue中更新UI,避免UI阻塞,无法响应用户操作:

  1. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{  
  2.     // long-running task   
  3.     dispatch_async(dispatch_get_main_queue(), ^{  
  4.         // update UI   
  5.     });  
  6. });  
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // long-running task
    dispatch_async(dispatch_get_main_queue(), ^{
        // update UI
    });
});

     上面提到dispatch_async这个接口,用来提交blcok给指定queue进行异步执行。这个接口会在成功提交block后立即返回,然后继续执行下去。由于block是定义在栈上的,所以需要将其复制到堆上,见这里

     与之相对应的是dispatch_sync接口,提交block以供同步执行。这个接口会等到block执行结束才返回,所以不需要复制block。So,如果在调用该接口在当前queue上指派任务,就会导致deadlock。维基百科上给了段示例代码:

  1. dispatch_queue_t exampleQueue = dispatch_queue_create("com.example.unique.identifier", NULL );  
  2. dispatch_sync( exampleQueue,^{  
  3.   dispatch_sync( exampleQueue,^{  
  4.     printf("I am now deadlocked...\n");  
  5.   });});  
  6. dispatch_release( exampleQueue );  
dispatch_queue_t exampleQueue = dispatch_queue_create("com.example.unique.identifier", NULL );
dispatch_sync( exampleQueue,^{
  dispatch_sync( exampleQueue,^{
    printf("I am now deadlocked...\n");
  });});
dispatch_release( exampleQueue );
     如果追求的是并发,那么dispatch_sync有什么用呢?关于dispatch_sync的用途,SO上有 讨论

     

2. Normal Control

  • dispatch_once

     如果没有记错的话,在iOS Con 2012上,大众点评的同学分享了个Topic叫《iOS开发最佳实践》,开篇讲singleton实现的演进(怎么演进都有可以挑的刺),后面转折说要把精力放到用户看得到的地方。

     如果把singleton和best practice放在一起,那么我很容易联想到dispatch_once这个函数,它可以保证整个应用程序生命周期中某段代码只被执行一次

  1. static dispatch_once_t onceToken;  
  2. dispatch_once(&onceToken, ^{  
  3.     // code to be executed once   
  4. });  
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    // code to be executed once
});

  • dispatch_after

     有时候我们需要等个几秒钟然后做个动画或者给个提示,这时候可以用dispatch_after这个函数:

  1. double delayInSeconds = 2.0;  
  2. dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);  
  3. dispatch_after(popTime, dispatch_get_main_queue(), ^(void){  
  4.     // code to be executed on the main queue after delay   
  5. });  
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    // code to be executed on the main queue after delay
});

  • dispatch_set_target_queue

     通过dispatch_set_target_queue函数可以设置一个dispatch queue的优先级,或者指定一个dispatch source相应的事件处理提交到哪个queue上。

  1. dispatch_set_target_queue(serialQ, globalQ);  
dispatch_set_target_queue(serialQ, globalQ);

  • dispatch_apply

     执行某个代码片段若干次。

  1. dispatch_apply(10, globalQ, ^(size_t index) {  
  2.     // do sth. 10 times   
  3. });  
dispatch_apply(10, globalQ, ^(size_t index) {
    // do sth. 10 times
});

  • dispatch group

     Dispatch Group机制允许我们监听一组任务是否完成:

  1. dispatch_group_t group = dispatch_group_create();  
  2. dispatch_group_async(group, concurrentQ, blk0);  
  3. dispatch_group_async(group, concurrentQ, blk1);  
  4. dispatch_group_async(group, concurrentQ, blk2);  
  5. dispatch_group_notify(group, mainQ, ^{  
  6.     // update UI   
  7. });  
  8. dispatch_release(group);  
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, concurrentQ, blk0);
dispatch_group_async(group, concurrentQ, blk1);
dispatch_group_async(group, concurrentQ, blk2);
dispatch_group_notify(group, mainQ, ^{
    // update UI
});
dispatch_release(group);

     或者说同步地等待一段时间看是否结束:

  1. dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 1ull * NSEC_PER_SEC);  
  2. dispatch_group_wait(group, time);  
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 1ull * NSEC_PER_SEC);
dispatch_group_wait(group, time);

  • dispatch_barrier_async

     通过dispatch_barrier_async函数提交的任务会等它前面的任务执行结束才开始,然后它后面的任务必须等它执行完毕才能开始。

  1. dispatch_async(concurrentQ, blk0);  
  2. dispatch_async(concurrentQ, blk1);  
  3. dispatch_barrier_async(concurrentQ, blk_barrier);  
  4. dispatch_async(concurrentQ, blk2);  
dispatch_async(concurrentQ, blk0);
dispatch_async(concurrentQ, blk1);
dispatch_barrier_async(concurrentQ, blk_barrier);
dispatch_async(concurrentQ, blk2);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值