GCD 并发 VS 串行 同步 VS 异步

210 阅读6分钟

并发队列

特点:同时调度多个任务(注意:也是按FIFO调度),不会等待上一个任务完成,再调度下一个。

一、并发队列 异步任务

为每个任务新创建一个线程执行。

    dispatch_queue_t concurrentQueue = dispatch_queue_create("com.my.concurrent", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(concurrentQueue, ^{
        NSLog(@"并发队列 异步任务0: %@", [NSThread currentThread]);
    });
    dispatch_async(concurrentQueue, ^{
        sleep(4);
        NSLog(@"并发队列 异步任务1: %@", [NSThread currentThread]);
    });
    dispatch_async(concurrentQueue, ^{
        sleep(3);
        NSLog(@"并发队列 异步任务2: %@", [NSThread currentThread]);
    });
    dispatch_async(concurrentQueue, ^{
        sleep(2);
        NSLog(@"并发队列 异步任务3: %@", [NSThread currentThread]);
    });
    dispatch_async(concurrentQueue, ^{
        sleep(1);
        NSLog(@"并发队列 异步任务4: %@", [NSThread currentThread]);
    });

--------并发队列 异步任务---------------
2018-03-13 10:39:11.282717+0800 GCDDemo[61398:17145606] 并发队列 异步任务0: <NSThread: 0x60400027ab40>{number = 3, name = (null)}
2018-03-13 10:39:12.287176+0800 GCDDemo[61398:17145602] 并发队列 异步任务4: <NSThread: 0x6040006616c0>{number = 4, name = (null)}
2018-03-13 10:39:13.287166+0800 GCDDemo[61398:17145605] 并发队列 异步任务3: <NSThread: 0x60000047efc0>{number = 5, name = (null)}
2018-03-13 10:39:14.287177+0800 GCDDemo[61398:17145603] 并发队列 异步任务2: <NSThread: 0x60400047c900>{number = 6, name = (null)}
2018-03-13 10:39:15.287222+0800 GCDDemo[61398:17145604] 并发队列 异步任务1: <NSThread: 0x60000047ee00>{number = 7, name = (null)}

二、并发队列 同步任务

在当前线程顺序执行;

虽然是并发队列,但由于是同步任务,当上一个任务未完成时,会阻塞当前线程,下一个任务也就无法执行。所以也是顺序执行的。

    dispatch_queue_t concurrentQueue = dispatch_queue_create("com.my.concurrent", DISPATCH_QUEUE_CONCURRENT);
    dispatch_sync(concurrentQueue, ^{
        sleep(4);
        NSLog(@"并发队列 同步任务1: %@", [NSThread currentThread]);
    });
    dispatch_sync(concurrentQueue, ^{
        sleep(3);
        NSLog(@"并发队列 同步任务2: %@", [NSThread currentThread]);
    });
    dispatch_sync(concurrentQueue, ^{
        sleep(2);
        NSLog(@"并发队列 同步任务3: %@", [NSThread currentThread]);
    });
    dispatch_sync(concurrentQueue, ^{
        sleep(1);
        NSLog(@"并发队列 同步任务4: %@", [NSThread currentThread]);
    });
2018-03-13 10:40:38.029652+0800 GCDDemo[61453:17148595] 并发队列 同步任务1: <NSThread: 0x6000000778c0>{number = 1, name = main}
2018-03-13 10:40:41.030824+0800 GCDDemo[61453:17148595] 并发队列 同步任务2: <NSThread: 0x6000000778c0>{number = 1, name = main}
2018-03-13 10:40:43.032137+0800 GCDDemo[61453:17148595] 并发队列 同步任务3: <NSThread: 0x6000000778c0>{number = 1, name = main}
2018-03-13 10:40:44.033434+0800 GCDDemo[61453:17148595] 并发队列 同步任务4: <NSThread: 0x6000000778c0>{number = 1, name = main}

串行队列

特点: 顺序的调度任务,上一个任务执行完毕,才会调度下一个任务。

一、串行队列 异步执行

创建一个新的线程,在新的线程中顺序执行。

虽然是异步任务,但是由于是同步队列,所以会在同一个线程上顺序调度,当前线程完成上一个任务时,才会执行下一个任务。

    dispatch_queue_t serialQueue = dispatch_queue_create("com.my.serial", DISPATCH_QUEUE_SERIAL);
    dispatch_async(serialQueue, ^{
        sleep(4);
        NSLog(@"串行队列 异步任务1: %@", [NSThread currentThread]);
    });
    dispatch_async(serialQueue, ^{
        sleep(3);
        NSLog(@"串行队列 异步任务2: %@", [NSThread currentThread]);
    });
    dispatch_async(serialQueue, ^{
        sleep(2);
        NSLog(@"串行队列 异步任务3: %@", [NSThread currentThread]);
    });
    dispatch_async(serialQueue, ^{
        sleep(1);
        NSLog(@"串行队列 异步任务4: %@", [NSThread currentThread]);
    });
2018-03-13 10:54:18.848320+0800 GCDDemo[61918:17171634] 串行队列 异步任务1: <NSThread: 0x6000002723c0>{number = 3, name = (null)}
2018-03-13 10:54:21.853179+0800 GCDDemo[61918:17171634] 串行队列 异步任务2: <NSThread: 0x6000002723c0>{number = 3, name = (null)}
2018-03-13 10:54:23.857731+0800 GCDDemo[61918:17171634] 串行队列 异步任务3: <NSThread: 0x6000002723c0>{number = 3, name = (null)}
2018-03-13 10:54:24.861741+0800 GCDDemo[61918:17171634] 串行队列 异步任务4: <NSThread: 0x6000002723c0>{number = 3, name = (null)}

二、串行队列 同步执行

顺序的在当前线程执行。

    dispatch_queue_t serialQueue = dispatch_queue_create("com.my.serial", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(serialQueue, ^{
        sleep(4);
        NSLog(@"串行队列 同步任务1: %@", [NSThread currentThread]);
    });
    dispatch_sync(serialQueue, ^{
        sleep(3);
        NSLog(@"串行队列 同步任务2: %@", [NSThread currentThread]);
    });
    dispatch_sync(serialQueue, ^{
        sleep(2);
        NSLog(@"串行队列 同步任务3: %@", [NSThread currentThread]);
    });
    dispatch_sync(serialQueue, ^{
        sleep(1);
        NSLog(@"串行队列 同步任务4: %@", [NSThread currentThread]);
    });
2018-03-13 10:55:29.318125+0800 GCDDemo[61966:17173944] 串行队列 同步任务1: <NSThread: 0x600000071d40>{number = 1, name = main}
2018-03-13 10:55:32.318892+0800 GCDDemo[61966:17173944] 串行队列 同步任务2: <NSThread: 0x600000071d40>{number = 1, name = main}
2018-03-13 10:55:34.319660+0800 GCDDemo[61966:17173944] 串行队列 同步任务3: <NSThread: 0x600000071d40>{number = 1, name = main}
2018-03-13 10:55:35.320929+0800 GCDDemo[61966:17173944] 串行队列 同步任务4: <NSThread: 0x600000071d40>{number = 1, name = main}

主队列(main queue)

特点:

  • 不会开启线程,所有任务都在主线程执行,无论同步还是异步;
  • 上一个任务执行完毕,才会调度下一个任务。(串行队列的性质)

一、主队列 异步任务

在主线程顺序执行。

    dispatch_async(dispatch_get_main_queue(), ^{
        sleep(4);
        NSLog(@"主队列 异步任务1:%@", [NSThread currentThread]);
    });
    dispatch_async(dispatch_get_main_queue(), ^{
        sleep(3);
        NSLog(@"主队列 异步任务2:%@", [NSThread currentThread]);
    });
    dispatch_async(dispatch_get_main_queue(), ^{
        sleep(2);
        NSLog(@"主队列 异步任务3:%@", [NSThread currentThread]);
    });
    dispatch_async(dispatch_get_main_queue(), ^{
        sleep(1);
        NSLog(@"主队列 异步任务4:%@", [NSThread currentThread]);
    });
2018-03-13 10:58:17.316804+0800 GCDDemo[62068:17179639] 主队列 异步任务1:<NSThread: 0x604000262540>{number = 1, name = main}
2018-03-13 10:58:20.318195+0800 GCDDemo[62068:17179639] 主队列 异步任务2:<NSThread: 0x604000262540>{number = 1, name = main}
2018-03-13 10:58:22.318997+0800 GCDDemo[62068:17179639] 主队列 异步任务3:<NSThread: 0x604000262540>{number = 1, name = main}
2018-03-13 10:58:23.320285+0800 GCDDemo[62068:17179639] 主队列 异步任务4:<NSThread: 0x604000262540>{number = 1, name = main}

二、主队列 同步任务

死锁

dispatch_sync会把一个同步任务追加到主队列(main queue)的队尾,同时阻塞当前线程。由于是同步队列,所以只有当该任务之前的所有任务调度执行完成以后,才会调度该任务。但是由于当前线程被阻塞了,之前的任务完成不了,然后也就无法调度当前任务,这就形成了死锁。

也就是说,任务队列等待线程完成任务,线程等待任务队列调度同步任务,相互等待,也就死锁了。

    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"主队列 同步任务1:%@", [NSThread currentThread]);
    });