dispatch group
是GCD的一项特性,能够把任务分组。调用者可以等待这组任务执行完毕,也可以在提供回调函数之后继续往下执行,这组任务完成时,调用者会得到通知。这个功能有许多用途,其中最重要、最值得注意的用法,就是把将要并发执行的多个任务合为一组,于是调用者就可以知道这些任务何时才能全部执行完毕。
-
dispatch_group_create
创建dispatch group
。dispatch_group_t group = dispatch_group_create();
-
dispatch_group_async
把异步任务提交到指定任务组和指定下拿出队列执行。void dispatch_group_async(dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block);
group ——对应的任务组,之后可以通过
dispatch_group_wait
或者dispatch_group_notify
监听任务组内任务的执行情况。queue ——block任务执行的线程队列,任务组内不同任务的队列可以不同。
block —— 执行任务的block。
-
dispatch_group_enter
用于添加对应任务组中的未执行完毕的任务数,执行一次,未执行完毕的任务数加1,当未执行完毕任务数为0的时候,才会使dispatch_group_wait
解除阻塞和dispatch_group_notify
的block执行。void dispatch_group_enter(dispatch_group_t group);
-
dispatch_group_leave
用于减少任务组中的未执行完毕的任务数,执行一次,未执行完毕的任务数减1,dispatch_group_enter
和dispatch_group_leave
要匹配,不然系统会认为group任务没有执行完毕。void dispatch_group_leave(dispatch_group_t group);
-
dispatch_group_wait
等待组任务完成,会阻塞当前线程,当任务组执行完毕时,才会解除阻塞当前线程。long dispatch_group_wait(dispatch_group_t group, dispatch_time_t timeout);
group ——需要等待的任务组。
timeout ——等待的超时时间(即等多久),单位为
dispatch_time_t
。如果设置为DISPATCH_TIME_FOREVER
,则会一直等待(阻塞当前线程),直到任务组执行完毕。
-
dispatch_group_notify
待任务组执行完毕时调用,不会阻塞当前线程。void dispatch_group_notify(dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block);
group ——需要监听的任务组。
queue ——block任务执行的线程队列,和之前group执行的线程队列无关。
block ——任务组执行完毕时需要执行的任务block。
dispatch_semaphore
dispatch_semaphore_create
dispatch_semaphore_t dispatch_semaphore_create(long value);
传入的参数为long,输出一个
dispatch_semaphore_t
类型且值为value的信号量。值得注意的是,这里的传入的参数value必须大于或等于0,否则
dispatch_semaphore_create
会返回NULL。
dispatch_semaphore_signal
long dispatch_semaphore_signal(dispatch_semaphore_t dsema);
这个函数会使传入的信号量dsema的值加1。
dispatch_semaphore_signal
的返回值为long类型,当返回值为0时表示当前并没有线程等待其处理的信号量,其处理的信号量的值加1即可。当返回值不为0时,表示其当前有(一个或多个)线程等待其处理的信号量,并且该函数唤醒了一个等待的线程(当线程有优先级时,唤醒优先级最高的线程;否则随机唤醒)。
dispatch_semaphore_wait
long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);
这个函数会使传入的信号量dsema的值减1。
这个函数的作用是这样的,如果dsema信号量的值大于0,该函数所处线程就继续执行下面的语句,并且将信号量的值减1。
如果desema的值为0,那么这个函数就阻塞当前线程等待timeout(注意timeout的类型为
dispatch_time_t
,不能直接传入整形或float型数)。如果等待的期间desema的值被
dispatch_semaphore_signal
函数加1了,且该函数(即dispatch_semaphore_wait
)所处线程获得了信号量,那么就继续向下执行并将信号量减1。如果等待期间没有获取到信号量或者信号量的值一直为0,那么等到timeout时,其所处线程自动执行其后语句。
dispatch_semaphore_wait
的返回值也为long型。当其返回0时表示在timeout之前,该函数所处的线程被成功唤醒。当其返回不为0时,表示timeout发生。
DISPATCH_TIME_NOW
与DISPATCH_TIME_FOREVER
- 在设置timeout时,比较有用的两个宏:
DISPATCH_TIME_NOW
和DISPATCH_TIME_FOREVER
。
- DISPATCH_TIME_NOW 表示当前;
- DISPATCH_TIME_FOREVER 表示遥远的未来;
一般可以直接设置timeout为这两个宏其中的一个,或者自己创建一个
dispatch_time_t
类型的变量。创建
dispatch_time_t
类型的变量有两种方法,dispatch_time
和dispatch_walltime
。利用创建
dispatch_time
创建dispatch_time_t
类型变量的时候一般也会用到这两个变量。
dispatch_time_t dispatch_time(dispatch_time_t when, int64_t delta);
- 其参数when需传入一个
dispatch_time_t
类型的变量,和一个delta值。表示when加delta时间就是timeout的时间。
dispatch_time_t t = dispatch_time(DISPATCH_TIME_NOW, 1*1000*1000*1000);
//表示当前时间向后延时一秒为timeout的时间。
实例代码
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSLog(@"group one start");
dispatch_group_async(group, queue, ^{
dispatch_async(queue, ^{
sleep(1); //这里线程睡眠1秒钟,模拟异步请求
NSLog(@"group one finish");
});
});
dispatch_group_notify(group, queue, ^{
NSLog(@"group finished");
});
在group中嵌套了一个异步任务时,group并没有等待group内的异步任务执行完毕才进入
dispatch_group_notify
中,这是因为,在dispatch_group_async
中又启了一个异步线程,而异步线程是直接返回的,所以group就认为是执行完毕了。通过
dispatch_group_enter
告知group,一个任务开始,未执行完毕任务数加1,在异步线程任务执行完毕时,通过dispatch_group_leave
告知group,一个任务结束,未执行完毕任务数减1,当未执行完毕任务数为0的时候,这时group才认为组内任务都执行完毕了(这个和GCD的信号量的机制有些相似),这时候才会回调dispatch_group_notify
中的block。
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSLog(@"group one start");
dispatch_group_enter(group);
dispatch_async(queue, ^{
sleep(1); //这里线程睡眠1秒钟,模拟异步请求
NSLog(@"group one finish");
dispatch_group_leave(group);
});
dispatch_group_notify(group, queue, ^{
NSLog(@"group finished");
});
要点
一系列任务可归入一个dispatch group中。开发者可以在这组执行完毕时获得通知。
通过dispatch group,可以在并发式派发队列中同时执行多项任务。此时GCD会根据系统资源来调度这些并发执行的任务。开发者若自己来实现此功能,则需要编写大量代码。