用示例阐明 GCD 的同步异步串行并行

2019-05-28  本文已影响0人  CoderSun

用示例阐明 GCD 的同步异步串行并行

[TOC]

示例

  1. 下文示例中所用到的宏定义有:

    GCD_TEST_LOG(task)

    NSLog(@"task:%@ main:%@ p:%p", task, NSThread.isMainThread ? @"1" : @"0", NSThread.currentThread)
    

    GCD_TEST_TASK_A

    GCD_TEST_LOG(@"A");
    NSLog(@"1");
    [NSThread sleepForTimeInterval:1.f];
    NSLog(@"2")
    

    GCD_TEST_TASK_B

    GCD_TEST_LOG(@"B");
    NSLog(@"4");
    [NSThread sleepForTimeInterval:1.f];
    NSLog(@"5")
    

    GCD_TEST_TASK_C

    GCD_TEST_LOG(@"C");
    NSLog(@"7");
    [NSThread sleepForTimeInterval:1.f];
    NSLog(@"8")
    

    GCD_TEST_TASK_D

    GCD_TEST_LOG(@"D");
    NSLog(@"10");
    [NSThread sleepForTimeInterval:1.f];
    NSLog(@"11")
    
  2. 下文示例代码在主线程中执行.

  3. 下文所用符号示意:

    ✅ 较常用.

    ⚠️ 极少使用, 或使用有风险, 或使用无意义.

  4. 为方便复制调试, 以上宏定义源码如下:

    #define GCD_TEST_LOG(task) NSLog(@"task:%@ main:%@ p:%p", task, NSThread.isMainThread ? @"1" : @"0", NSThread.currentThread)
    
    #define GCD_TEST_TASK_A \
    GCD_TEST_LOG(@"A"); \
    NSLog(@"1"); \
    [NSThread sleepForTimeInterval:1.f]; \
    NSLog(@"2")
    
    #define GCD_TEST_TASK_B \
    GCD_TEST_LOG(@"B"); \
    NSLog(@"4"); \
    [NSThread sleepForTimeInterval:1.f]; \
    NSLog(@"5")
    
    #define GCD_TEST_TASK_C \
    GCD_TEST_LOG(@"C"); \
    NSLog(@"7"); \
    [NSThread sleepForTimeInterval:1.f]; \
    NSLog(@"8")
    
    #define GCD_TEST_TASK_D \
    GCD_TEST_LOG(@"D"); \
    NSLog(@"10"); \
    [NSThread sleepForTimeInterval:1.f]; \
    NSLog(@"11")
    

main_queue

dispatch_sync ⚠️

dispatch_queue_t main_queue = dispatch_get_main_queue();
dispatch_sync(main_queue, ^{ GCD_TEST_TASK_A; });       // 1 | 2
NSLog(@"3");                                            // 3
dispatch_sync(main_queue, ^{ GCD_TEST_TASK_B; });       // 4 | 5
NSLog(@"6");                                            // 6
dispatch_sync(main_queue, ^{ GCD_TEST_TASK_C; });       // 7 | 8
NSLog(@"9");                                            // 9
dispatch_sync(main_queue, ^{ GCD_TEST_TASK_D; });       // 10 | 11
NSLog(@"12");                                           // 12

输出

崩溃在第 2 行

Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)

如在其它线程执行以上代码, 则正常执行. 如下:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    dispatch_queue_t main_queue = dispatch_get_main_queue();
    dispatch_sync(main_queue, ^{ GCD_TEST_TASK_A; });       // 1 | 2
    NSLog(@"3");                                            // 3
    dispatch_sync(main_queue, ^{ GCD_TEST_TASK_B; });       // 4 | 5
    NSLog(@"6");                                            // 6
    dispatch_sync(main_queue, ^{ GCD_TEST_TASK_C; });       // 7 | 8
    NSLog(@"9");                                            // 9
    dispatch_sync(main_queue, ^{ GCD_TEST_TASK_D; });       // 10 | 11
    NSLog(@"12");                                           // 12
});

输出

2017-02-11 17:59:28.471943+0800 sun[68420:10866547] task:A main:1 p:0x600001449f40
2017-02-11 17:59:28.472160+0800 sun[68420:10866547] 1
2017-02-11 17:59:29.472686+0800 sun[68420:10866547] 2
2017-02-11 17:59:29.472918+0800 sun[68420:10866746] 3
2017-02-11 17:59:29.474518+0800 sun[68420:10866547] task:B main:1 p:0x600001449f40
2017-02-11 17:59:29.474743+0800 sun[68420:10866547] 4
2017-02-11 17:59:30.475987+0800 sun[68420:10866547] 5
2017-02-11 17:59:30.476268+0800 sun[68420:10866746] 6
2017-02-11 17:59:30.476631+0800 sun[68420:10866547] task:C main:1 p:0x600001449f40
2017-02-11 17:59:30.476804+0800 sun[68420:10866547] 7
2017-02-11 17:59:31.478109+0800 sun[68420:10866547] 8
2017-02-11 17:59:31.478349+0800 sun[68420:10866746] 9
2017-02-11 17:59:31.478600+0800 sun[68420:10866547] task:D main:1 p:0x600001449f40
2017-02-11 17:59:31.478784+0800 sun[68420:10866547] 10
2017-02-11 17:59:32.480031+0800 sun[68420:10866547] 11
2017-02-11 17:59:32.480304+0800 sun[68420:10866746] 12

dispatch_async ✅

dispatch_queue_t main_queue = dispatch_get_main_queue();
dispatch_async(main_queue, ^{ GCD_TEST_TASK_A; });      // 1 | 2
NSLog(@"3");                                            // 3
dispatch_async(main_queue, ^{ GCD_TEST_TASK_B; });      // 4 | 5
NSLog(@"6");                                            // 6
dispatch_async(main_queue, ^{ GCD_TEST_TASK_C; });      // 7 | 8
NSLog(@"9");                                            // 9
dispatch_async(main_queue, ^{ GCD_TEST_TASK_D; });      // 10 | 11
NSLog(@"12");                                           // 12

输出

2017-02-11 18:00:19.191572+0800 sun[68464:10868282] 3
2017-02-11 18:00:19.191773+0800 sun[68464:10868282] 6
2017-02-11 18:00:19.191927+0800 sun[68464:10868282] 9
2017-02-11 18:00:19.192077+0800 sun[68464:10868282] 12
2017-02-11 18:00:19.192433+0800 sun[68464:10868282] task:A main:1 p:0x6000028cdf40
2017-02-11 18:00:19.192569+0800 sun[68464:10868282] 1
2017-02-11 18:00:20.193589+0800 sun[68464:10868282] 2
2017-02-11 18:00:20.193928+0800 sun[68464:10868282] task:B main:1 p:0x6000028cdf40
2017-02-11 18:00:20.194083+0800 sun[68464:10868282] 4
2017-02-11 18:00:21.194587+0800 sun[68464:10868282] 5
2017-02-11 18:00:21.194946+0800 sun[68464:10868282] task:C main:1 p:0x6000028cdf40
2017-02-11 18:00:21.195064+0800 sun[68464:10868282] 7
2017-02-11 18:00:22.195342+0800 sun[68464:10868282] 8
2017-02-11 18:00:22.195688+0800 sun[68464:10868282] task:D main:1 p:0x6000028cdf40
2017-02-11 18:00:22.195850+0800 sun[68464:10868282] 10
2017-02-11 18:00:23.197078+0800 sun[68464:10868282] 11

global_queue

dispatch_sync ⚠️

dispatch_queue_t global_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_sync(global_queue, ^{ GCD_TEST_TASK_A; });     // 1 | 2
NSLog(@"3");                                            // 3
dispatch_sync(global_queue, ^{ GCD_TEST_TASK_B; });     // 4 | 5
NSLog(@"6");                                            // 6
dispatch_sync(global_queue, ^{ GCD_TEST_TASK_C; });     // 7 | 8
NSLog(@"9");                                            // 9
dispatch_sync(global_queue, ^{ GCD_TEST_TASK_D; });     // 10 | 11
NSLog(@"12");                                           // 12

输出

2017-02-11 18:01:21.071692+0800 sun[68510:10869926] task:A main:1 p:0x600002912a40
2017-02-11 18:01:21.071854+0800 sun[68510:10869926] 1
2017-02-11 18:01:22.073179+0800 sun[68510:10869926] 2
2017-02-11 18:01:22.073418+0800 sun[68510:10869926] 3
2017-02-11 18:01:22.073596+0800 sun[68510:10869926] task:B main:1 p:0x600002912a40
2017-02-11 18:01:22.073717+0800 sun[68510:10869926] 4
2017-02-11 18:01:23.074995+0800 sun[68510:10869926] 5
2017-02-11 18:01:23.075236+0800 sun[68510:10869926] 6
2017-02-11 18:01:23.075391+0800 sun[68510:10869926] task:C main:1 p:0x600002912a40
2017-02-11 18:01:23.075554+0800 sun[68510:10869926] 7
2017-02-11 18:01:24.076513+0800 sun[68510:10869926] 8
2017-02-11 18:01:24.076904+0800 sun[68510:10869926] 9
2017-02-11 18:01:24.077053+0800 sun[68510:10869926] task:D main:1 p:0x600002912a40
2017-02-11 18:01:24.077247+0800 sun[68510:10869926] 10
2017-02-11 18:01:25.078505+0800 sun[68510:10869926] 11
2017-02-11 18:01:25.078753+0800 sun[68510:10869926] 12

dispatch_async ✅

dispatch_queue_t global_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(global_queue, ^{ GCD_TEST_TASK_A; });    // 1 | 2
NSLog(@"3");                                            // 3
dispatch_async(global_queue, ^{ GCD_TEST_TASK_B; });    // 4 | 5
NSLog(@"6");                                            // 6
dispatch_async(global_queue, ^{ GCD_TEST_TASK_C; });    // 7 | 8
NSLog(@"9");                                            // 9
dispatch_async(global_queue, ^{ GCD_TEST_TASK_D; });    // 10 | 11
NSLog(@"12");                                           // 12

输出

2017-02-11 18:02:06.159847+0800 sun[68554:10871641] 3
2017-02-11 18:02:06.159892+0800 sun[68554:10871805] task:A main:0 p:0x60000163a2c0
2017-02-11 18:02:06.160052+0800 sun[68554:10871641] 6
2017-02-11 18:02:06.160065+0800 sun[68554:10871805] 1
2017-02-11 18:02:06.160098+0800 sun[68554:10871784] task:B main:0 p:0x60000190ec80
2017-02-11 18:02:06.160241+0800 sun[68554:10871641] 9
2017-02-11 18:02:06.160247+0800 sun[68554:10871784] 4
2017-02-11 18:02:06.160263+0800 sun[68554:10871797] task:C main:0 p:0x600001639dc0
2017-02-11 18:02:06.160404+0800 sun[68554:10871641] 12
2017-02-11 18:02:06.160439+0800 sun[68554:10871787] task:D main:0 p:0x60000165e080
2017-02-11 18:02:06.161688+0800 sun[68554:10871787] 10
2017-02-11 18:02:06.161892+0800 sun[68554:10871797] 7
2017-02-11 18:02:07.160298+0800 sun[68554:10871805] 2
2017-02-11 18:02:07.160484+0800 sun[68554:10871784] 5
2017-02-11 18:02:07.166661+0800 sun[68554:10871787] 11
2017-02-11 18:02:07.166676+0800 sun[68554:10871797] 8

custom_queue

DISPATCH_QUEUE_SERIAL

dispatch_sync ⚠️
dispatch_queue_t custom_queue = dispatch_queue_create("custom_queue", DISPATCH_QUEUE_SERIAL);
dispatch_sync(custom_queue, ^{ GCD_TEST_TASK_A; });     // 1 | 2
NSLog(@"3");                                            // 3
dispatch_sync(custom_queue, ^{ GCD_TEST_TASK_B; });     // 4 | 5
NSLog(@"6");                                            // 6
dispatch_sync(custom_queue, ^{ GCD_TEST_TASK_C; });     // 7 | 8
NSLog(@"9");                                            // 9
dispatch_sync(custom_queue, ^{ GCD_TEST_TASK_D; });     // 10 | 11
NSLog(@"12");                                           // 12

输出

2017-02-11 18:02:46.126540+0800 sun[68594:10873135] task:A main:1 p:0x600001657880
2017-02-11 18:02:46.126753+0800 sun[68594:10873135] 1
2017-02-11 18:02:47.128070+0800 sun[68594:10873135] 2
2017-02-11 18:02:47.128445+0800 sun[68594:10873135] 3
2017-02-11 18:02:47.128615+0800 sun[68594:10873135] task:B main:1 p:0x600001657880
2017-02-11 18:02:47.128740+0800 sun[68594:10873135] 4
2017-02-11 18:02:48.129982+0800 sun[68594:10873135] 5
2017-02-11 18:02:48.130324+0800 sun[68594:10873135] 6
2017-02-11 18:02:48.130498+0800 sun[68594:10873135] task:C main:1 p:0x600001657880
2017-02-11 18:02:48.130619+0800 sun[68594:10873135] 7
2017-02-11 18:02:49.131752+0800 sun[68594:10873135] 8
2017-02-11 18:02:49.131942+0800 sun[68594:10873135] 9
2017-02-11 18:02:49.132027+0800 sun[68594:10873135] task:D main:1 p:0x600001657880
2017-02-11 18:02:49.132119+0800 sun[68594:10873135] 10
2017-02-11 18:02:50.132608+0800 sun[68594:10873135] 11
2017-02-11 18:02:50.132791+0800 sun[68594:10873135] 12
dispatch_async ✅
dispatch_queue_t custom_queue = dispatch_queue_create("custom_queue", DISPATCH_QUEUE_SERIAL);
dispatch_async(custom_queue, ^{ GCD_TEST_TASK_A; });    // 1 | 2
NSLog(@"3");                                            // 3
dispatch_async(custom_queue, ^{ GCD_TEST_TASK_B; });    // 4 | 5
NSLog(@"6");                                            // 6
dispatch_async(custom_queue, ^{ GCD_TEST_TASK_C; });    // 7 | 8
NSLog(@"9");                                            // 9
dispatch_async(custom_queue, ^{ GCD_TEST_TASK_D; });    // 10 | 11
NSLog(@"12");                                           // 12

输出

2017-02-11 18:03:31.083347+0800 sun[68633:10874631] 3
2017-02-11 18:03:31.083393+0800 sun[68633:10874809] task:A main:0 p:0x600000d71800
2017-02-11 18:03:31.083545+0800 sun[68633:10874631] 6
2017-02-11 18:03:31.083569+0800 sun[68633:10874809] 1
2017-02-11 18:03:31.083704+0800 sun[68633:10874631] 9
2017-02-11 18:03:31.083910+0800 sun[68633:10874631] 12
2017-02-11 18:03:32.085991+0800 sun[68633:10874809] 2
2017-02-11 18:03:32.086343+0800 sun[68633:10874809] task:B main:0 p:0x600000d71800
2017-02-11 18:03:32.086501+0800 sun[68633:10874809] 4
2017-02-11 18:03:33.087598+0800 sun[68633:10874809] 5
2017-02-11 18:03:33.087961+0800 sun[68633:10874809] task:C main:0 p:0x600000d71800
2017-02-11 18:03:33.088119+0800 sun[68633:10874809] 7
2017-02-11 18:03:34.091592+0800 sun[68633:10874809] 8
2017-02-11 18:03:34.091858+0800 sun[68633:10874809] task:D main:0 p:0x600000d71800
2017-02-11 18:03:34.092052+0800 sun[68633:10874809] 10
2017-02-11 18:03:35.096494+0800 sun[68633:10874809] 11

DISPATCH_QUEUE_CONCURRENT

dispatch_sync ⚠️

等效 global_queue | dispatch_sync

dispatch_queue_t custom_queue = dispatch_queue_create("custom_queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(custom_queue, ^{ GCD_TEST_TASK_A; });     // 1 | 2
NSLog(@"3");                                            // 3
dispatch_sync(custom_queue, ^{ GCD_TEST_TASK_B; });     // 4 | 5
NSLog(@"6");                                            // 6
dispatch_sync(custom_queue, ^{ GCD_TEST_TASK_C; });     // 7 | 8
NSLog(@"9");                                            // 9
dispatch_sync(custom_queue, ^{ GCD_TEST_TASK_D; });     // 10 | 11
NSLog(@"12");                                           // 12

输出

2017-02-11 18:04:13.914992+0800 sun[68678:10876152] task:A main:1 p:0x600000de6a80
2017-02-11 18:04:13.915168+0800 sun[68678:10876152] 1
2017-02-11 18:04:14.915620+0800 sun[68678:10876152] 2
2017-02-11 18:04:14.915822+0800 sun[68678:10876152] 3
2017-02-11 18:04:14.915926+0800 sun[68678:10876152] task:B main:1 p:0x600000de6a80
2017-02-11 18:04:14.916103+0800 sun[68678:10876152] 4
2017-02-11 18:04:15.916831+0800 sun[68678:10876152] 5
2017-02-11 18:04:15.917190+0800 sun[68678:10876152] 6
2017-02-11 18:04:15.917319+0800 sun[68678:10876152] task:C main:1 p:0x600000de6a80
2017-02-11 18:04:15.917427+0800 sun[68678:10876152] 7
2017-02-11 18:04:16.918675+0800 sun[68678:10876152] 8
2017-02-11 18:04:16.918918+0800 sun[68678:10876152] 9
2017-02-11 18:04:16.919083+0800 sun[68678:10876152] task:D main:1 p:0x600000de6a80
2017-02-11 18:04:16.919277+0800 sun[68678:10876152] 10
2017-02-11 18:04:17.920562+0800 sun[68678:10876152] 11
2017-02-11 18:04:17.920799+0800 sun[68678:10876152] 12
dispatch_async ✅

等效 global_queue| dispatch_async

dispatch_queue_t custom_queue = dispatch_queue_create("custom_queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(custom_queue, ^{ GCD_TEST_TASK_A; });    // 1 | 2
NSLog(@"3");                                            // 3
dispatch_async(custom_queue, ^{ GCD_TEST_TASK_B; });    // 4 | 5
NSLog(@"6");                                            // 6
dispatch_async(custom_queue, ^{ GCD_TEST_TASK_C; });    // 7 | 8
NSLog(@"9");                                            // 9
dispatch_async(custom_queue, ^{ GCD_TEST_TASK_D; });    // 10 | 11
NSLog(@"12");                                           // 12

输出

2017-02-11 18:04:53.590727+0800 sun[68716:10877557] 3
2017-02-11 18:04:53.590749+0800 sun[68716:10877625] task:A main:0 p:0x6000022c4d80
2017-02-11 18:04:53.590956+0800 sun[68716:10877557] 6
2017-02-11 18:04:53.590976+0800 sun[68716:10877625] 1
2017-02-11 18:04:53.590980+0800 sun[68716:10877635] task:B main:0 p:0x6000022afd00
2017-02-11 18:04:53.591153+0800 sun[68716:10877557] 9
2017-02-11 18:04:53.591198+0800 sun[68716:10877639] task:C main:0 p:0x6000022b25c0
2017-02-11 18:04:53.591205+0800 sun[68716:10877635] 4
2017-02-11 18:04:53.591335+0800 sun[68716:10877557] 12
2017-02-11 18:04:53.591379+0800 sun[68716:10877639] 7
2017-02-11 18:04:53.591403+0800 sun[68716:10877641] task:D main:0 p:0x6000022c5c80
2017-02-11 18:04:53.592740+0800 sun[68716:10877641] 10
2017-02-11 18:04:54.593739+0800 sun[68716:10877625] 2
2017-02-11 18:04:54.593756+0800 sun[68716:10877639] 8
2017-02-11 18:04:54.593756+0800 sun[68716:10877635] 5
2017-02-11 18:04:54.593756+0800 sun[68716:10877641] 11

总结

总结只有一点, 个人认为这一点是理解 线程 上的 任务任务串行并行 的核心要点. 而 dispatch_syncdispatch_async 则是在某一 线程 下调度某一 线程队列 的行为, 其行为是 平行相对 的.

  1. dispatch_syncdispatch_async 都是相对当前线程, 死锁与否都是相对当前添加任务所在线程.

对于任务的串行并行, 无需再赘述.

上一篇下一篇

猜你喜欢

热点阅读