Grand Central Dispatch (GCD) 用法详细介绍

1. Dispatch Queue
执行处理有两种Dispatch Queue。
一种是等待现在执行中的处理的Serial Dispatch Queue。(顺序执行)
另一种是不等待现在执行中处理的Concurrent Dispatch Queue。(并行执行)

Concurrent Dispatch Queue执行:
线程0线程1线程2线程3
blk0blk1blk2blk3
blk5blk6blk4 
blk7   


2. dispatch_queue_create
通过 dispatch_queue_create 函数可以生成 Dispathch Queue。

// 第一个参数为queue署名。第二个参数为创建的queue类型。null默认为Serial dispatch queue
dispatch_queue_t myDispatchQueue = dispatch_queue_create(“com.example.queue”, NULL);

// dispatch_queue_t myDispatchQueue = dispatch_queue_create(“com.example.queue”, DIDPATCH_QUEUE_CONCURRENT);

dispatch_async(myDispatchQueue, ^{ NSLog(@“ block on queue “); });

// 结束后需要release
dispatch_release(myDispatchQueue);

// 相应的有retain函数
// dispatch_retain(myDispatchQueue);

虽然一执行完 dispatch_async 后里面释放queue,但是由于Block持有该Dispatch Queue,所以此处release后 queue 不会被废弃。


3. Main Dispatch Queue 和 Global Dispatch Queue
以上两种为系统标准提供的Dispatch Queue;

名称Dispatch Queue种类说明
Main Dispatch QueueSerial Dispatch Queue主线程执行
DISPATCH_QUEUE_PRIORITY_HIGHConcurrent Dispatch Queue高优先级
DISPATCH_QUEUE_PRIORITY_DEFAULTConcurrent Dispatch Queue默认优先级
DISPATCH_QUEUE_PRIORITY_LOWConcurrent Dispatch Queue低优先级
DISPATCH_QUEUE_PRIORITY_BACKGROUNDConcurrent Dispatch Queue后台执行

// 获取主线程
dispatch_queue_t mainDispatchQueue = dispatch_get_main_queue();

// 
dispatch_queue_t globalDispatchQueueHigh = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);

// 
dispatch_queue_t globalDispatchQueueDefault = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

// 
dispatch_queue_t globalDispatchQueueLow = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);

// 
dispatch_queue_t globalDispatchQueueBackground = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);

注:dispatch_retain() 和 dispatch_release() 对于这两种queue不会引起任何变化。


4. dispatch_set_target_queue
dispatch_queue_create() 函数生成的无论是Serial 还是 Concurrent ,都是默认优先级。
使用 dispatch_set_target_queue 可以变更优先级。
例如:
dispatch_queue_t myDispatchQueue = dispatch_queue_create(“com.example.queue”, NULL);
dispatch_queue_t globalDispatchQueueBackground = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_set_target_queue(myDispatchQueue, globalDispatchQueueBackground);

以上代码将 myDispatchQueue 的优先级变更为 后台优先级。


5. dispatch_after
想要在指定时间后执行处理,可使用 dispatch_after。
例如:3秒后将指定的Block 追加奥 Main Dispatch Queue 中。

dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3ull * NSEC_PER_SEC);
dispatch_after(time, dispatch_get_main_queue(), ^{ NSLog(@“waited at least three seconds.”); });

注: dispatch_after 函数并不是在指定时间后执行处理,而是在指定时间后追加处理到Dispatch Queue。例如Main Dispatch Queue在主线程的RunLoop中执行。所以在比如每隔1/60秒执行的RunLoop,Block最快在3秒后执行,最慢在 3+1/60秒后执行。


6. Dispatch Group
如果想要在追加到多个Dispatch Queue中的多个处理全部结束后执行结束处理,,可使用Dispatch Group。
例如:

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, ^{NSLog(@“bll0”);});
dispatch_group_async(group, queue, ^{NSLog(@“bll1”);});
dispatch_group_async(group, queue, ^{NSLog(@“bll2”);});

dispatch_group_notify(group, dispatch_get_main_queue(), ^{ NSLog(@“done”); });
dispatch_release(group);


其中可以使用 dispatch_group_wait函数仅等待全部处理执行结束:
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, ^{NSLog(@“bll0”);});
dispatch_group_async(group, queue, ^{NSLog(@“bll1”);});
dispatch_group_async(group, queue, ^{NSLog(@“bll2”);});

dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_release(group); 

注:dispatch_group_wait 的返回值为0,标识全部处理执行结束;
返回值不为0,表示经过了指定时间,属于Dispatch Group 的某一个处理还在执行中;
由于 DISPATCH_TIME_FOREVER 标识永久等待,故而返回值恒为0;

dispatch_group_wait 可能会造成当前线程停止,直至所有处理执行结束。

7. dispatch_barrier_async
在多个并行处理之间插入指定处理后再继续多个并行处理。
例如:
dispatch_queue_t queue = dispatch_queue_create(“com.example.queue”, DISPATCH_QUEUE_CONCURRENT);

dispatch_async(queue, blk0_for_reading); 
dispatch_async(queue, blk1_for_reading); 
dispatch_async(queue, blk2_for_reading); 
dispatch_async(queue, blk3_for_reading); 
dispatch_barrier_async(queue, blk_for_writing);
dispatch_async(queue, blk4_for_reading); 
dispatch_async(queue, blk5_for_reading); 
dispatch_async(queue, blk6_for_reading); 
dispatch_async(queue, blk7_for_reading); 
dispatch_async(queue, blk8_for_reading); 

dispatch_release(queue);

使用 Concurrent Dispatch Queue 和 dispatch_barrier_async 可实现高效率的数据库访问和文件访问。


8. dispatch_apply
该函数按指定的次数将指定的Block追加到指定的Dispatch Queue中,并等待全部处理执行结束。
例如:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(5, queue, ^(size_t index){ NSLog(@“%zu”, index); });
NSLog(@“done”);

// 运行结果
4
1
0
3
2
done


9. dispatch_suspend / dispatch_resume
当追加大量处理到Dispatch Queue时,在追加处理的过程中,希望不执行一追加的处理,例如验算结果被Block截获时,一些处理会对这个演算结果造成影响。
可使用以上两个函数挂起和恢复queue。


10. Dispatch Semaphore
该函数是比 dispatch_barrier_async() 更细粒度的排他控制。
先看一下例子:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSMutableArray *array = [[NSMutableArray alloc] init];
for(int i = 0; i< 100000; ++i)
{
     dispatch_async(queue, ^{ [array addObject:[NSNumber numberWithInt:i]]; });
}


以上代码执行后由内存错误导致应用异常结束的概率很高。
Dispatch Semaphore 是持有计数的信号。当计数为0时,表示等待;计数为1或者大于1时,减去1而不等待;

// 生成函数,计数初始值为1
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);

// 一直等待,直到Dispatch Semaphore 的计数值达到大于等于1;
long result = dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
if (result == 0)
{
     // 可执行其他需要进行排他控制的处理
}else{
     // 在达到指定时间为止待机
}

修改后的例子:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 保证可访问NSMutableArray 的线程同时只能有一个
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);

NSMutableArray *array = [[NSMutableArray alloc] init];
for(int i = 0; i< 100000; ++i)
{
     dispatch_async(queue, ^{ 
          dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
          [array addObject:[NSNumber numberWithInt:i]]; 
     });
} 
dispatch_release(semaphore);


11. dispatch_once
dispatch_once 函数保证在应用程序执行中只执行一次指定处理的API;
例如:
static int initialized = NO;
if (initialized == NO)
{
     //initialized
     initialized = YES;
}


可转变成:
static dispatch_once_t pred;
dispatch_once(&pred, ^{
     //initialized
});





































  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值