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。

 

你可能感兴趣的:(多线程)