GCD多线程的使用(四)
关于dispatch_set_target_queue和dispatch_after的使用。
使用GCD的函数dispatch_queue_create创建的Dispatch Queue(Serial Dispatch Queue和Concurrent Dispatch Queue)使用的优先级都是默认优先级,有时根据需求可能会变更优先级,变更优先级要使用dispatch_set_target_queue函数。下面是创建一个低优先级的Serial Dispatch Queue示例:
/** * 创建一个低优先级的Serial Dispatch Queue */ - (void)createLowPrioritySerialDispatchQueue { dispatch_queue_t queue = dispatch_queue_create("com.hxp.queue", DISPATCH_QUEUE_SERIAL); //此时的优先级为默认优先级 dispatch_queue_t targetQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0); //创建一个低优先级的目标Global Dispatch Queue dispatch_set_target_queue(queue, targetQueue); //更改优先级为目标Dispatch Queue的优先级 }
dispatch_set_target_queue函数的第一个参数是需要变更优先级的Dispatch Queue,第二个参数是指定要使用的执行优先级相同优先级的Global Dispatch Queue,即目标Dispatch Queue。
另外,dispatch_set_target_queue函数还有指定执行顺序的功能呢,先看代码和输出结果:
dispatch_queue_t queue0 = dispatch_queue_create("com.hxp.queue0", DISPATCH_QUEUE_SERIAL); dispatch_queue_t queue1 = dispatch_queue_create("com.hxp.queue1", DISPATCH_QUEUE_SERIAL); dispatch_queue_t queue2 = dispatch_queue_create("com.hxp.queue2", DISPATCH_QUEUE_SERIAL); dispatch_queue_t queue3 = dispatch_queue_create("com.hxp.queue3", DISPATCH_QUEUE_SERIAL); dispatch_queue_t queue4 = dispatch_queue_create("com.hxp.queue4", DISPATCH_QUEUE_SERIAL); dispatch_async(queue0, ^{ NSLog(@"%@:queue0", [NSThread currentThread]); }); dispatch_async(queue1, ^{ NSLog(@"%@:queue1", [NSThread currentThread]); }); dispatch_async(queue2, ^{ NSLog(@"%@:queue2", [NSThread currentThread]); }); dispatch_async(queue3, ^{ NSLog(@"%@:queue3", [NSThread currentThread]); }); dispatch_async(queue4, ^{ NSLog(@"%@:queue4", [NSThread currentThread]); });
正常的输出结果应该是顺序杂乱无章,并发执行:
2015-06-19 07:01:12.885 GCD_Study[23054:3603] {name = (null), num = 6}:queue4 2015-06-19 07:01:12.885 GCD_Study[23054:1303] {name = (null), num = 2}:queue0 2015-06-19 07:01:12.885 GCD_Study[23054:3403] {name = (null), num = 5}:queue2 2015-06-19 07:01:12.885 GCD_Study[23054:3503] {name = (null), num = 3}:queue3 2015-06-19 07:01:12.885 GCD_Study[23054:3107] {name = (null), num = 4}:queue1
然后使用dispatch_set_target_queue函数指定优先级后:
dispatch_queue_t queue0 = dispatch_queue_create("com.hxp.queue0", DISPATCH_QUEUE_SERIAL); dispatch_queue_t queue1 = dispatch_queue_create("com.hxp.queue1", DISPATCH_QUEUE_SERIAL); dispatch_queue_t queue2 = dispatch_queue_create("com.hxp.queue2", DISPATCH_QUEUE_SERIAL); dispatch_queue_t queue3 = dispatch_queue_create("com.hxp.queue3", DISPATCH_QUEUE_SERIAL); dispatch_queue_t queue4 = dispatch_queue_create("com.hxp.queue4", DISPATCH_QUEUE_SERIAL); dispatch_set_target_queue(queue1, queue0); dispatch_set_target_queue(queue2, queue0); dispatch_set_target_queue(queue3, queue0); dispatch_set_target_queue(queue4, queue0); dispatch_async(queue0, ^{ NSLog(@"%@:queue0", [NSThread currentThread]); }); dispatch_async(queue1, ^{ NSLog(@"%@:queue1", [NSThread currentThread]); }); dispatch_async(queue2, ^{ NSLog(@"%@:queue2", [NSThread currentThread]); }); dispatch_async(queue3, ^{ NSLog(@"%@:queue3", [NSThread currentThread]); }); dispatch_async(queue4, ^{ NSLog(@"%@:queue4", [NSThread currentThread]); });
这次是使用dispatch_set_target_queue函数指定目标为一个Serial Dispatch Queue,输出结果:
2015-06-19 07:16:11.244 GCD_Study[23239:1303] {name = (null), num = 2}:queue0 2015-06-19 07:16:11.246 GCD_Study[23239:1303] {name = (null), num = 2}:queue1 2015-06-19 07:16:11.247 GCD_Study[23239:1303] {name = (null), num = 2}:queue2 2015-06-19 07:16:11.248 GCD_Study[23239:1303] {name = (null), num = 2}:queue3 2015-06-19 07:16:11.250 GCD_Study[23239:1303] {name = (null), num = 2}:queue4
原本并行执行的多个Serial Dispatch Queue变成了串行执行。在必须将不可并行执行的处理追加到多个Serial Dispatch Queue中时,如果用dispatch_set_target_queue函数将目标指定为某一个Serial Dispatch Queue,即可防止处理并行执行。
想象这样一个场景:我想在几秒后执行某一个操作。这样的场景就需要用到dispatch_after函数了。下面的代码是在2秒后输出一个字符串:
- (void)dispatchAfter { dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 2ull * NSEC_PER_SEC); dispatch_queue_t queue = dispatch_get_main_queue(); NSLog(@"Now"); dispatch_after(time, queue, ^{ NSLog(@"after 2sec"); }); }
输出结果:
2015-06-19 07:46:20.182 GCD_Study[23269:607] Now 2015-06-19 07:46:22.183 GCD_Study[23269:607] after 2sec
虽然有误差,但大概也是2秒后了。因为dispatch_after函数并不是在指定的时间后执行处理,而是在指定的时间追加处理到Dispatch Queue。上面那段代码意思是在2秒后将执行任务的Block用dispatch_async追加到Main Dispatch Queue中。
下面说一下dispatch_after函数的三个参数。第一个参数是指定时间用的dispatch_time_t类型的值,该值用dispatch_time函数或者dispatch_walltime函数获得。dispatch_time函数获取的是从第一个参数指定的时间开始,到第二个参数指定的毫微秒单位时间后的时间。上面的代码中第一个参数用的DISPATCH_TIME_NOW,表示从现在开始,第二个参数是2ull*NSEC_PER_SEC,表示延迟2秒,合起来就是从现在开始2秒后将Block追加到Main Dispatch Queue中。
数值和NSEC_PER_SEC的乘积得到单位为毫微秒的数值。有以下取值
#define NSEC_PER_USEC 1000ull /* nanoseconds per microsecond */ #define USEC_PER_SEC 1000000ull /* microseconds per second */ #define NSEC_PER_SEC 1000000000ull /* nanoseconds per second */ #define NSEC_PER_MSEC 1000000ull /* nanoseconds per millisecond */
NSEC_PER_USEC:1000纳秒/1微秒
USEC_PER_SEC :1000000微秒/1秒
NSEC_PER_SEC :1000000000纳秒/1秒
NSEC_PER_MSEC:1000000纳秒/1毫秒
ull是C语言中得数值字面量,是显示表明类型时使用的字符串,表示unsigned long long。