资料来源《Objective-C高级编程 iOS与OS X多线程和内存管理》
苹果官方对GCD的说明:
开发者要做的只是定义想执行的任务并追加到适当的Dispatch Queue中。
这句话用源代码表示:
dispatch_async(queue, ^{
/*
* 想执行的任务
*/
});
源代码使用Block语法“定义想执行的任务”,通过dispatch_async函数“追加”赋值在变量queue的“Dispatch Queue中”。仅这样就可使指定的Block在另一线程中执行。
存在两种Dispatch Queue,一种是等待现在执行中处理的Serial Dispatch Queue(串行队列),另一种是不等待现在执行中处理的Concurrent Dispatch Queue(并行队列)。

dispatch_queue_create
通过dispatch_queue_create函数可生成Dispatch Queue
dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("com.gcd.mySerialDispatchQueue", NULL);
dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("com.gcd.MySerialDispatchQueue", DISPATCH_QUEUE_SERIAL);
Concurrent Dispatch Queue并行执行多个追加处理了,而Serial Dispatch Queue同时只能执行一个追加处理。虽然Serial Dispatch Queue和Concurrent Dispatch Queue受到系统资源的显示,但用dispatch_queue_create函数可生成任意多个Dispatch Queue。当生成多个Serial Dispatch Queue时,各个Serial Dispatch Queue将并行执行。
生成Serial Dispatch Queue时,将第二个参数指定为NULL。生成Concurrent Dispatch Queue时,第二个参数指定为
dispatch_queue_t myConcurrentDispatchQueue = dispatch_queue_create("com.gcd.myConcurrentDispatchQueue", DISPATCH_QUEUE_CONCURRENT);
注:虽然Serial Dispatch Queue和Concurrent Dispatch Queue受到系统资源的限制,但用dispatch_queue_create函数可生成任意多个Dispatch Queue。当生成多个Serial Dispatch Queue时,各个Serial Dispatch Queue将并行执行。如果过多使用多线程,就会消耗大量内存,引起大量的上下文切换,大幅度降低系统的响应性能。
遗憾的是尽管有ARC这一通过编译器自动管理内存的优秀技术,但生成的Dispatch Queue必须邮程序员负责释放。这是因为Dispatch Queue并没有像Block那样具有作为Objective-C对象来处理的技术。
Main Dispatch Queue/Global Dispatch Queue
Main Dispatch Queue是在主线程中执行的Dispatch Queue。因为主线程只有一个,所以Main Dispatch Queue自然就是Serial Dispatch Queue。
Global Dispatch Queue是所有应用程序都能够使用的Concurrent Dispatch Queue。没有必要通过dispatch_queue_create函数逐个生成Concurrent Dispatch Queue。只要获取Global Dispatch Queue即可。
另外,Global Dispatch Queue有4个执行优先级,分别是高优先级(High Priority)、默认优先级(Default Priority)、低优先级(Low Priority)和后台优先级(Background Priority)。通过XNU内核管理的用于Global Dispatch Queue的线程,将各自使用的Global Dispatch Queue的执行优先级作为线程的执行优先级使用。但不能保证实时性,因此执行优先级只是大致的判断。
/**
Global Dispatch Queue(高优先级)的获取方法
*/
dispatch_queue_t globalDispatchQueueHigh = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
/**
Global Dispatch Queue(默认优先级)的获取方法
*/
dispatch_queue_t globalDispatchQueueDefault = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
/**
Global Dispatch Queue(低优先级)的获取方法
*/
dispatch_queue_t globalDispatchQueueLow = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
/**
Global Dispatch Queue(后台先级)的获取方法
*/
dispatch_queue_t globalDispatchQueueBackground = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
/**
在默认优先级的Global Dispatch Queue中执行Block
*/
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
/**
可并行执行的处理
*/
/**
在 Main Dispatch Queue中执行Block
*/
dispatch_async(dispatch_get_main_queue(), ^{
/**
只能在主线程中执行的处理
*/
});
});
dispatch_set_target_queue
dispatch_queue_create函数生成的Dispatch Queue不管是Serial Dispatch Queue还是Concurrent Dispatch Queue,都使用与默认优先级Global Dispatch Queue相同执行优先级的线程。而变更生成的Dispatch Queue的执行优先级要使用dispatch_set_target_queue函数。在后台执行动作处理的Serial Dispatch Queue的生成方法如下:
/**
指定要变更执行优先级的Dispatch Queue为dispatch_set_target_queue函数的第一个参数
指定与要使用的执行优先级相同优先级的Global Dispatch Queue为第二个参数(目标)
第一个参数如果指定系统提供的Main Dispatch Queue和Global Dispatch Queue则不知道会出现什么状况,因此这些均不可指定。
*/
dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("com.gcd.MySerialDispatchQueue", NULL);
dispatch_queue_t globalDispatchQueueBackground = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_set_target_queue(mySerialDispatchQueue, globalDispatchQueueBackground);
dispatch_after
想在指定时间后执行处理的情况,可使用dispatch_after函数来实现。
/**
第一个参数是指定时间用的dispatch_time_t类型的值,第二个参数指定要追加处理的Dispatch Queue
dispatch_time_t:
第一个参数经常使用的值是DISPATCH_TIME_NOW,表示现在的时间
第二个参数数值和NSEC_PER_SEC的乘积得到单位为毫秒的数值,“ull”是C语言的数值字面量,是显示表明类型时使用的字符串(表示“unsigned long long”)。如果使用NSEC_PER_MSEC则可以以毫秒为单位计算
*/
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。
Dispatch Group
在追加到Dispatch Queue中的多个处理全部结束后想执行结束处理。
/**
因为向Global Dispatch Queue即Concurrent Dispatch Queue追加处理,多个线程并行执行,所以追加处理的执行顺序不定。
执行时会发生变化,但是此执行结果的done一定是最后输出的。
dispatch_group_create函数生成dispatch_group_t类型的Dispatch Group
dispatch_group_async与dispatch_async函数相同,都追加Block到指定的Dispatch Queue中
dispatch_group_notify函数第一个参数指定为要监视的Dispatch Group,在追加到该Dispatch Group的全部处理执行结束时,将第三个参数的Block追加到第二个参数的Dispatch Queue中。
*/
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(@"blk0");
});
dispatch_group_async(group, queue, ^{
NSLog(@"blk1");
});
dispatch_group_async(group, queue, ^{
NSLog(@"blk2");
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"done");
});
一旦检测到所有处理执行结束,就可将结束的处理追加到Dispatch Queue中。
另外。在Dispatch Group中也可以使用dispatch_group_wait函数仅等待全部处理执行结束。
//第二个参数指定为等待时间(超时)DISPATCH_TIME_FOREVER意味着永久等待
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_barrier_async
dispatch_barrier_async函数会等待追加到Concurrent Dispatch Queue 上的并行执行的处理全部结束之后,再将指定的处理追加到该Concurrent Dispatch Queue中。然后在由dispatch_barrier_async函数追加的处理执行完毕后,Concurrent Dispatch Queue才恢复为一般的动作。追加到该Concurrent Dispatch Queue的处理又开始并行执行。

dispatch_async(queue, block1);
dispatch_async(queue, block2);
dispatch_async(queue, block3);
dispatch_barrier_async(queue, block);
dispatch_async(queue, block4);
dispatch_async(queue, block5);
dispatch_sync
将指定的block同步追加到指定的Dispatch Queue中。在追加block结束之前,dispatch_sync函数会一直等待。
一旦调用dispatch_sync函数,那么在指定的处理执行结束之前,该函数不会返回。dispatch_sync函数可简化源代码,也可说是简易版的dispatch_group_wait函数。
但也容易引起死锁:
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_sync(queue, ^{
NSLog(@"hello");
});
dispatch_apply
//第一个参数为重复次数,第二个参数为追加对象的Dispatch,第三个参数为追加的处理
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(10, queue, ^(size_t index) {
NSLog(@"%zu",index);
});
NSLog(@"done");
dispatch_suspend / dispatch_resume
dispatch_suspend函数挂起指定的Dispatch Queue
dispatch_suspend(queue);
dispatch_resume函数恢复指定的Dispatch Queue
dispatch_resume(queue);
dispatch_once
dispatch_once函数是保证在应用程序执行中只执行一次指定处理的API
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
/**
初始化
*/
});
网友评论