关于GCD的API(2)
4.dispatch_after
想在指定时间后执行处理的情况,可使用dispatch_after函数来实现。
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_time_t类型的值。该值使用dispatch_time函数或dispatch_walltime函数作成。
第二个参数指定要追加处理的Dispatch Queue.
第三个参数指定记述要执行处理的Block。
dispatch_after函数并不是在指定时间后执行处理,而只是在指定时间追加处理到Dispatch Queue。也就是说此源代码可以理解为,3秒后用dispatch_async函数追加Block到Main Dispatch Queue相同。
因为Main Dispatch Queue在主线程的RunLoop中执行,所以在比如每隔1/60秒执行的RunLoop中,Block最快3秒后执行,最慢在3 + 1/60 秒后执行,并且Main Dispatch Queue有大量处理追加或主线程的处理本身有延迟时,这个时间会更长。
所以dispatch_after在想大致延迟执行处理时,非常有效,在严格时间的要求下还是尽量不使用。
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW,3ull * NSEC_PER_SEC);
dispatch_time函数能够获取从第一个参数dispatch_time_t类型值中指定的时间开始,到第二个参数指定的毫微秒单位时间后的时间。
dispatch_walltime函数由POSIX中使用的struct timeespec类型的时间得到dispatch_time_t类型的值。
dispatch_time函数通常用于计算相对时间,而dispatch_walltime函数用于计算绝对时间。
“ull”是C语言的数值字面亮,是显示表明类型时使用的字符串(表示“unsigned long long”)。
5.Dispatch Group
在追加到Dispatch Queue中的多个处理全部结束后想执行结束处理,在Serial Dispatch Queue实现简单,但是在使用Concurrent Dispatch Queue 时或同时使用多个Dispatch Queue时,就会变得复杂。
这种情况下使用Dispatch Group:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t groupQueue = dispatch_group_create();
dispatch_group_async(groupQueue, queue, ^{
NSLog(@"1");
});
dispatch_group_async(groupQueue, queue, ^{
NSLog(@"2");
});
dispatch_group_async(groupQueue, queue, ^{
NSLog(@"3");
});
dispatch_group_notify(groupQueue, dispatch_get_main_queue(), ^{
NSLog(@"end");
});
因为向Concurrent Dispatch Queue追加处理,多个线程并行执行,所以追加处理的执行顺序不定。
Dispatch Group函数一旦检测到所有处理执行结束,就可将结束的处理追加到Dispatch Queue中。
dispatch_group_notify函数,第一个参数指定为要监视的Dispatch Group。在追加到该Dispatch Group的全部处理执行结束时,将第三个参数的Block追加到第二个参数的Dispatch Queue中。
另外,在Dispatch Group中也可以使用dispatch_group_wait函数仅等待全部处理执行结束。
这里的“等待”意味着一旦调用dispatch_group_wait函数,该函数就处于调用状态而不返回,即执行该函数的当前线程停止。也就是在经过函数中指定的时间或属于指定的Dispatch Group的处理全部执行结束之前,执行该函数的线程停止。
dispatch_group_wait函数会返回long类型的一个值,为0时,代表Dispatch Group 的全部处理执行结束;不为0时,代表虽然经过了指定的时间,但是某一个处理还在执行中。
当等待为时间为DISPATCH_TIME_FOREVER、由dispatch_group_wait函数返回时,由于属于Dispatch Group的处理必定全部执行结束,因此返回值恒为0。
不过,一般情形下,还是推荐使用dispatch_group_notify函数,因为该函数可以简化源代码。
6.dispatch_barrier_async
在访问数据库或文件时,为了避免数据竞争,以及高效率的进行访问,读取处理追加到Concurrent Dispatch Queue中,写入处理在任一个读取处理没有执行的状态下,追加到Serial Dispatch Queue中即可。
GCD提供很聪明简便的解决办法--dispatch_barrier_async函数。该函数同dispatch_queue_create函数生成的Concurrent Dispatch Queue一起使用。
dispatch_async(queue, blk0_for_reading);
dispatch_async(queue, blk1_for_reading);
dispatch_async(queue, blk2_for_reading);
dispatch_barrier_async(queue, blk_for_writing);
dispatch_async(queue, blk3_for_reading);
dispatch_async(queue, blk4_for_reading);
像上述源代码所示,在将dispatch_barrier_async函数追加到Concurrent Dispatch Queue中以后,之前的并行执行的处理全部结束之后,然后执行dispatch_barrier_async,在该函数执行完毕时,Concurrent Dispatch Queue才恢复为一般的动作,才会追加到Concurrent Dispatch Queue的处理又开始并行执行。