美文网首页
GCD-并发队列/串行队列,同步/异步

GCD-并发队列/串行队列,同步/异步

作者: thinkq | 来源:发表于2016-08-20 17:45 被阅读758次

    学多线程时,不注意总结老是学学忘忘,今天特地总结下。只为总结留作资料,参考了许多博客内容,如有博主不爽请留言,立马删除

    队列

    GCD的队列可以分为2大类型

    并发队列(Concurrent Dispatch Queue):

    并行队列是指队列中的任务可以并发地执行,即开始执行队首的任务后,不必等其执行完毕就可以接着开始执行队首之后的任务,因此在某一时刻可能存在同时执行的多个任务(使用多个多个线程)。

    串行队列(Serial Dispatch Queue)

    串行队列是指队列中的任务是一个接一个地执行的,队首的任务执行完毕后才能执行其后面的任务,直至执行队尾的任务(使用一个线程)

    0FBC2146-4845-4063-82D2-6E64BA61F236.png

    代码:

        dispatch_async(queue, ^{
            NSLog(@"0");
        });
        dispatch_async(queue, ^{
            NSLog(@"1");
        });
        dispatch_async(queue, ^{
            NSLog(@"2");
        });
        dispatch_async(queue, ^{
            NSLog(@"3");
        });
        dispatch_async(queue, ^{
            NSLog(@"4");
        });
        dispatch_async(queue, ^{
            NSLog(@"5");
        });
        dispatch_async(queue, ^{
            NSLog(@"6");
        });
        dispatch_async(queue, ^{
            NSLog(@"7");
        });
        dispatch_async(queue, ^{
            NSLog(@"8");
        });
        dispatch_async(queue, ^{
            NSLog(@"9");
        });
    

    如果queue是Concurrent Dispatch Queue时,不用等当前正在执行的任务处理结束。首先执行任务0,不管任务0的执行是否结束都开始执行任务1,如此反复。并且不一定哪个先执行完成,所以打印结果是乱序。
    打印结果:

    2016-08-20 16:59:27.630 GCDDemo[8064:888741] 2
    2016-08-20 16:59:27.630 GCDDemo[8064:888756] 1
    2016-08-20 16:59:27.630 GCDDemo[8064:888739] 0
    2016-08-20 16:59:27.630 GCDDemo[8064:888738] 3
    2016-08-20 16:59:27.631 GCDDemo[8064:888791] 4
    2016-08-20 16:59:27.632 GCDDemo[8064:888741] 6
    2016-08-20 16:59:27.632 GCDDemo[8064:888792] 5
    2016-08-20 16:59:27.632 GCDDemo[8064:888793] 7
    2016-08-20 16:59:27.632 GCDDemo[8064:888756] 8
    2016-08-20 16:59:27.632 GCDDemo[8064:888794] 9
    

    如果queue是Serial Dispatch Queue时,任务挨个执行,任务0执行结束,接着执行任务1,如此反复。打印结果一定是有顺序的
    打印结果为:

    2016-08-20 17:07:25.717 GCDDemo[8093:897228] 0
    2016-08-20 17:07:25.717 GCDDemo[8093:897228] 1
    2016-08-20 17:07:25.718 GCDDemo[8093:897228] 2
    2016-08-20 17:07:25.718 GCDDemo[8093:897228] 3
    2016-08-20 17:07:25.718 GCDDemo[8093:897228] 4
    2016-08-20 17:07:25.718 GCDDemo[8093:897228] 5
    2016-08-20 17:07:25.718 GCDDemo[8093:897228] 6
    2016-08-20 17:07:25.719 GCDDemo[8093:897228] 7
    2016-08-20 17:07:25.719 GCDDemo[8093:897228] 8
    2016-08-20 17:07:25.719 GCDDemo[8093:897228] 9
    

    创建方式:

    并发队列(Concurrent Dispatch Queue):

    (1)GCD默认已经提供了全局的并发队列,供整个应用使用,获取方式:

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    

    第二个参数是为了以后扩展使用的,现在你只需要往里传入0。,第一个参数为优先级,全局并发队列的优先级有四个

    #define DISPATCH_QUEUE_PRIORITY_HIGH 2 //高
    #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默认
    #define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低
    #define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后台
    

    你可以通过传递DISPATCH_QUEUE_PRIORITY_HIGH和DISPATCH_QUEUE_PRIORITY_LOW常量来分别获取高和低优先级的队列。如你所料,高优先级并发队列中的任务要在默认和低优先级队列中的任务之前执行。同样的,在默认优先级队列中的任务要在低优先级队列中的任务之前执行。

    (2)用dispatch_queue_create函数创建

    dispatch_queue_t queue = dispatch_queue_create("com.private.ConcurrentQueue",DISPATCH_QUEUE_CONCURRENT);
    

    第一个参数为队列名称,第二个参数为队列类型(串行和并发):

    DISPATCH_QUEUE_CONCURRENT //并发队列
    DISPATCH_QUEUE_SERIAL // 串行队列,和填入NULL等价
    

    串行队列(Serial Dispatch Queue)

    (1)主队列是GCD自带的一种特殊的串行队列,放在主队列中的任务,都会放到主线程中执行

    使用dispatch_get_main_queue()获得主队列

    dispatch_queue_t queue = dispatch_get_main_queue();
    

    (2)使用dispatch_queue_create函数创建

    dispatch_queue_t queue = dispatch_queue_create("com.private.SerialQueue", DISPATCH_QUEUE_SERIAL);
    

    同步/异步

    同步和异步是针对当前代码流(即当前线程)和加入队列中的任务之间执行顺序的关系而言的。以同步的方式向队列中添加任务会阻塞当前线程,直到同步到队列中的任务执行完毕返回后,才会接着执行当前的代码流;以异步的方式向队列中添加的任务则不会阻塞当前线程,将任务添加到队列中后,不用等待任务执行完毕,即刻执行当前代码流。

    同步(dispatch_sync):

    dispatch_sync(myQueue,^{ printf("1"); //任务 1 });
    printf("2"); 
    dispatch_sync(myQueue,^{ printf("3"); //任务 3 });
    printf("4");
    

    上面的代码执行结果只有一种可能,即输出“1234”。

    在将输出 1 的任务(即代码中任务 1)同步到队列 myQueue 中后,当前线程阻塞,等待任务 1 执行完毕并返回后(即输出 1 之后),才能接着执行当前线程,输出 2。输出 2 之后,当前代码流继续运行,将任务 3 再同步到队列 myQueue 中后,当前线程阻塞,等待任务 3 执行,输出 3,之后当前代码流继续运行输出 4。

    这段代码的输出结果与 myQueue 是串行队列还是并行队列没有关系。
    异步(dispatch_async):

    dispatch_async(serialQueue,^{ printf("1"); //任务 1 }); 
    printf("2"); 
    dispatch_async(serialQueue,^{ printf("3"); //任务 3 }); 
    printf("4");
    

    上面代码执行结果可能为 “1234”、“1243”、“2134”、“2143”、“2413” 中的一种,2 始终在 4 前面,1 始终在 3 前面(注意:此例中的队列(serialQueue)为串行队列,串行队列的概念将在后文讲述),2 始终在 3 前面。

    将任务 1 异步添加到队列 serialQueue 中之后,不需要等待其执行完毕,当前代码流就继续执行了。当前代码流输出 2 时,可能任务 1 还没执行,也可能执行完毕了,因此 1 可能在 2 前输出也可能在 2 后输出;

    同理,将任务 3 异步添加到队列 serialQueue 中之后,不需要等待其执行完毕,当前代码流就继续执行。当前代码流输出 4 时,可能任务 3 还没执行,也可能执行完毕了,因此 3 可能在 4 前输出也可能在 4 后输出。

    对于当前代码流,输出 2 一定在 输出 4 前执行,因此 2 必定在 4 前输出。

    对于串行队列 serialQueue ,任务 1 一定在 任务 3 前执行,因此 1 必定在 3 前输出。

    将任务 3 添加到队列 serialQueue 的操作必定在输出 2 后进行,因此 2 必定在 3 前输出。

    总结:
    串行队列里的任务不能并发执行,只能一个接一个地执行,同一时刻该串行队列里的任务最多只有一个在执行;并发队列里的任务后面的任务不必等待前面的任务执行完毕再执行,可以多个同时执行,同一时刻该并行队列里的任务可以有多个正在执行。
    同步异步描述的是当前线程或代码流是否要阻塞以等待加入队列的任务执行完毕:同步要阻塞当前线程;异步不会阻塞当前线程。

    参考:
    http://www.cnblogs.com/wendingding/p/3806821.html
    http://huuang.com/?p=83
    《Objective-C高级编程 iOS与OS X多线程和内存管理》

    相关文章

      网友评论

          本文标题:GCD-并发队列/串行队列,同步/异步

          本文链接:https://www.haomeiwen.com/subject/lwsisttx.html