GCD(Grand Central Dispatch) API复
1、dispatch_queue_create
// 示例: 创建一个并行队列
dispatch_queue_t queue = dispatch_queue_create("com.myapp.queue", DISPATCH_QUEUE_CONCURRENT);
第一个参数为队列的名字,一般使用倒置域名来设置;第二个参数是创建队列的类型:有DISPATCH_QUEUE_SERIAL
和DISPATCH_QUEUE_CONCURRENT
两个参数。
2、获取系统的queue
- 获取 main queue:
dispatch_get_main_queue()
- 获取 global queue :
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
获取全局队列时,第一个参数为队列的优先级;第二个参数为标志位,一般设置为0。优先级可供的选项有4个:
DISPATCH_QUEUE_PRIORITY_HIGH
DISPATCH_QUEUE_PRIORITY_DEFAULT
DISPATCH_QUEUE_PRIORITY_LOW
DISPATCH_QUEUE_PRIORITY_BACKGROUND
3、dispatch_async
向队列中异步提交Block,不等待Block执行结束。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^ {
// ...
});
4、dispatch_sync
与 dispatch_async 类似,不过是同步向队列提交任务;需要等待block执行完成。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_sync(queue, ^ {
// ...
});
在使用 dispatc_sync 时,注意不要造成死锁,以下代码均会造成死锁:
// 死锁
dispatch_async(dispatch_get_main_queue(), ^ {
dispatch_sync(dispatch_get_main_queue(), ^ {
// ...
});
});
不仅仅是 main_queue 会造成死锁,serial queue 使用如上的代码都会造成死锁。
5、dispatch_after
在指定的时间间隔后,将Block提交到指定队列中;注意不是先提交,然后等待指定时间间隔后执行。
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 3.0);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_after(time, queue, ^ {
// do sth ..
});
6、dispatch_group
可以使用该API,实现如下功能,在 TASK A 、B 、C 都异步完成后执行TASK D。
dispatch_group的相关API有:
dispatch_group_t dispatch_group_create(void)
void dispatch_group_async(dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block)
void dispatch_group_async_f(dispatch_group_t group, dispatch_queue_t queue, void * context, dispatch_function_t work)
long dispatch_group_wait(dispatch_group_t group, dispatch_time_t timeout)
void dispatch_group_notify(dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block)
void dispatch_group_notify_f(dispatch_group_t group, dispatch_queue_t queue, void * context, dispatch_function_t work)
void dispatch_group_enter(dispatch_group_t group)
void dispatch_group_leave(dispatch_group_t group)
使用示例:
// example 1:
- (void)groupUse1 {
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_group_async(group, queue, ^ {
// Task A ..
NSLog(@"Task A");
[NSThread sleepForTimeInterval:2.0];
});
dispatch_group_async(group, queue, ^ {
// Task B ..
NSLog(@"Task B");
[NSThread sleepForTimeInterval:1.5];
});
dispatch_group_async(group, queue, ^ {
// Task C ..
NSLog(@"Task C");
[NSThread sleepForTimeInterval:1.0];
});
dispatch_group_notify(group, queue, ^ {
// Task D ..
NSLog(@"Task D");
});
}
// example 2
- (void)groupUse2 {
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_group_enter(group);
dispatch_async(queue, ^ {
// Task A ..
NSLog(@"Task A");
[NSThread sleepForTimeInterval:2.0];
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_async(queue, ^ {
// Task B ..
NSLog(@"Task B");
[NSThread sleepForTimeInterval:1.5];
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_async(queue, ^ {
// Task C ..
NSLog(@"Task C");
[NSThread sleepForTimeInterval:1.0];
dispatch_group_leave(group);
});
dispatch_group_notify(group, queue, ^ {
// Task D ..
NSLog(@"Task D");
});
}
// example 3
void taskA(void *context) {
NSLog(@"%s",__func__);
[NSThread sleepForTimeInterval:2.0];
NSLog(@"%s finished.",__func__);
}
void taskB(void *context) {
NSLog(@"%s",__func__);
[NSThread sleepForTimeInterval:1.0];
NSLog(@"%s finished.",__func__);
}
void taskC(void *context) {
NSLog(@"%s",__func__);
[NSThread sleepForTimeInterval:0.8];
NSLog(@"%s finished.",__func__);
}
- (void)use_dispatch_group_3 {
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_group_async_f(group, queue, (__bridge void *)self, &taskA);
dispatch_group_async_f(group, queue, (__bridge void *)self, &taskB);
dispatch_group_async_f(group, queue, (__bridge void *)self, &taskC);
dispatch_group_notify(group, queue, ^{
NSLog(@"Task D");
});
}
可以使用dispatch_group_wait设置一个超时时间,等待添加到组中的任务执行,如果超时时间内所有与该组相关的任务都完成了,该函数会返回0,未完成的话则反回非0。
- (void)use_dispatch_group_1 {
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
NSLog(@"Group 1 : Doing task 1.");
[NSThread sleepForTimeInterval:1];
NSLog(@"Group 1 : Task 1 finished.");
});
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
NSLog(@"Group 1 : Doing task 2.");
[NSThread sleepForTimeInterval:3];
NSLog(@"Group 1 : Task 2 finished.");
});
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
NSLog(@"Group 1 : Doing task 3.");
[NSThread sleepForTimeInterval:2];
NSLog(@"Group 1 : Task 3 finished.");
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"Group 1 : All tasks have done.");
});
dispatch_async(dispatch_get_global_queue(0, 0), ^{
long ret = dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, 1.5 * NSEC_PER_SEC));
if (ret != 0) {
NSLog(@"Group 1 : 超时 我等不及了~");
}
else {
NSLog(@"Group 1 : 终于等到你");
}
});
}
7、dispatch_barrier_async & dispatch_barrier_sync
当使用void dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block)
和void dispatch_barrier_sync(dispatch_queue_t queue, dispatch_block_t block)
时,会等待已经加入到了queue
中的Block
会执行完成,然后再执行dispatch_barrier_async、dispatch_barrier_sync
加入的任务(设为 Task barrier),当Task barrier执行完成后才继续执行其他加入到queue
中的任务。
可以用于如下的情况,假设有多个线程会对文件进行读写,读操作可以多个线程一起执行,但是写操作不能够与其他任意操作(读或写)一起执行。
- 只能用于 CONCURRENT QUEUE
- 不能用于获取的 Global Queue
// 示例
- (void)use_dispatch_barrier_async {
dispatch_queue_t queue = dispatch_queue_create("com.mytest.gcd", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^ {
NSLog(@"Reading A ...");
[NSThread sleepForTimeInterval:2.0];
NSLog(@"Reading A finised");
});
dispatch_async(queue, ^ {
NSLog(@"Reading B ...");
[NSThread sleepForTimeInterval:1.0];
NSLog(@"Reading B finised");
});
dispatch_barrier_async(queue, ^ {
NSLog(@"Writing ...");
[NSThread sleepForTimeInterval:5.0];
NSLog(@"Writing finised");
});
dispatch_async(queue, ^ {
NSLog(@"Reading C ...");
[NSThread sleepForTimeInterval:3.0];
NSLog(@"Reading C finised");
});
dispatch_async(queue, ^ {
NSLog(@"Reading D ...");
[NSThread sleepForTimeInterval:0.8];
NSLog(@"Reading D finised");
});
}
8、dispatch_semaphore
该用于控制并发量,当设置并发量为1时,可以当做互斥锁来用。
dispatch_semaphore_t sema = dispatch_semaphore_create(1);
NSMutableArray *mArray = [NSMutableArray array];
for(int i = 0; i < 10000; i ++) {
dispatch_async(dispatch_get_global_queue(0,0), ^ {
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
[mArray addObject:[[NSObject alloc] init]];
dispatch_semaphore_signal(sema);
});
}
9、dispatch_apply
函数原型为:void dispatch_apply(size_t iterations, dispatch_queue_t queue, void(^block)(size_t))
。
该函数一般用于多次的重复操作;可以用于 serial 和 concurrent 队列。当queue制定为并发队列时,一定要保证多线程操作时是安全的。
dispatch_apply
会等待所有任务都执行完成。
// 示例
NSArray *nums = @[@1,@2,@3,@4,@5];
dispatch_apply(nums.count, dispatch_get_global_queue(0, 0), ^ (size_t index) {
NSLog(@"%@",nums[index]);
});
NSLog(@"Apply Finished.");
10、dispatch_once
用于只执行一次的任务,是线程安全的;常常用于单例的创建。
函数原型:void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block);
dispatch_once
定义:typedef long dispatch_once_t;
// 使用示例:
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^ {
// do sth.
});
11、dispatch_set_target_queue
函数原型:void dispatch_set_target_queue(dispatch_object_t object, dispatch_queue_t queue);
设置dispatch_object_t
的目标队列;其目标队列负责该object的一系列进程。当设置某些object
的目标队列后将改变其相关的一些属性;具体如下:
-
dispatch_queue_t
- 可以修改其优先级,需要修改优先级时,通过
dispatch_get_global_queue
来获取正确优先级的 target queue 。 - 对于 SERIAL QUEUE ,如果将其 target queue 设置为另一个 SERIAL QUEUE ,那么提交到它和它 target queue 中的(或者其他target queue与其target queue 相同的串行队列)block将不会并发执行。
- 可以修改其优先级,需要修改优先级时,通过
注意:使用时不要造成循环设置。
-
dispatch_source
- dispatch_source的target queue 表明了其事件回调和取消回调的Block在哪里提交。
-
dispatch I/O
- dispatch I/O的target queue 指明了I/O操作在哪里执行。
12、dispatch_suspend & dispatch_resume
用于挂起和重新执行。
13、dispatch_I/O
用于在读取较大文件时,将文件分割成小块并行读取。
14、dispatch_source
dispatch_source
时BSD内核惯有的kqueue的包装,当内核发生各种事件时,它是一个提供给应用层面处理逻辑的接口。
其能够处理的事件如下:
类型 | 描述 |
---|---|
DISPATCH_SOURCE_TYPE_DATA_ADD | 变量增加 |
DISPATCH_SOURCE_TYPE_DATA_OR | 变量OR |
DISPATCH_SOURCE_TYPE_DATA_REPLACE | 变量替换 |
DISPATCH_SOURCE_TYPE_MACH_SEND | MACH 端口发送 |
DISPATCH_SOURCE_TYPE_MACH_RECV | MACH 端口接受 |
DISPATCH_SOURCE_TYPE_MEMORYPRESSURE | |
DISPATCH_SOURCE_TYPE_PROC | 检测到与进程相关的事件 |
DISPATCH_SOURCE_TYPE_READ | 可读取文件映像 |
DISPATCH_SOURCE_TYPE_SIGNAL | 接收信号 |
DISPATCH_SOURCE_TYPE_TIMER | 定时器 |
DISPATCH_SOURCE_TYPE_VNODE | 文件系统有变更 |
DISPATCH_SOURCE_TYPE_WRITE | 可写入文件映像 |
下面是已timer为例:
// ARC下需要外部保留timer强引用
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
dispatch_source_set_event_handler(timer, ^{
NSLog(@"___🙃");
dispatch_source_cancel(timer);
});
dispatch_resume(timer);