美文网首页
iOS GCD 串行和并发队列的理解

iOS GCD 串行和并发队列的理解

作者: 大风天上来 | 来源:发表于2019-05-24 15:42 被阅读0次

    首先看串行队列同步异步任务的请求顺序

    /**
     测试串行队列
     */
    - (void)testSerialQueue {
        dispatch_queue_t serialQueue = dispatch_queue_create("com.snake", DISPATCH_QUEUE_SERIAL);
        
        dispatch_sync(serialQueue, ^{
            NSLog(@"1 %@", [NSThread currentThread]);
        });
        
        dispatch_async(serialQueue, ^{
            sleep(5);
            NSLog(@"2 %@", [NSThread currentThread]);
        });
        
        dispatch_sync(serialQueue, ^{
            NSLog(@"3 %@", [NSThread currentThread]);
        });
        
        dispatch_async(serialQueue, ^{
            NSLog(@"4 %@", [NSThread currentThread]);
        });
    }
    
    

    运行结果


    串行队列,同步异步任务执行

    运行结果显示:任务依次执行,异步会创建新线程。

    • 结论:串行队列中的任务以FIFO方式从序列中执行,一次只调度一个任务(无论同步异步,前面任务执行完了,才开启下一个任务),异步任务会创建新的线程(文末的参考链接中,同步异步都在同一个线程执行,初步估计是iOS旧版本的原因,新系统变更的关系)。

    看看并行队列异步任务的执行结果

    - (void)testSerialQueue {
        dispatch_queue_t serialQueue = dispatch_queue_create("com.snake", DISPATCH_QUEUE_CONCURRENT);
        for (int i = 0 ; i < 20; i ++) {
            dispatch_async(serialQueue, ^{
                NSLog(@"%d %@",i, [NSThread currentThread]);
            });
        }
    }
    
    并行队列,异步任务

    从运行结果可以看出,并发会创建多个线程,而且并发队列中的线程是可以重复利用的(线程池)。

    并发队列的同步任务

    - (void)testSerialQueue {
        dispatch_queue_t serialQueue = dispatch_queue_create("com.snake", DISPATCH_QUEUE_CONCURRENT);
        for (int i = 0 ; i < 20; i ++) {
            dispatch_sync(serialQueue, ^{
                NSLog(@"%d %@",i, [NSThread currentThread]);
            });
        }
    }
    
    并发队列,同步任务

    从运行结果可以看出,并发队列的同步任务,没有创建新的线程,都在主线程依次执行

    • 并行和并发
      • 并发:两个或多个事件在同一时间间隔内发生。同一时间内只有一个任务执行
        例如单CPU的处理多线程;
      • 并行:两个或多个事件在同一时刻发生。同一时间内可能有多个任务执行
        例如多CPU的处理多线程;

    串行队列同步任务的执行顺序

    /**
     测试串行队列
     */
    - (void)testSerialQueue {
        dispatch_queue_t serialQueue = dispatch_queue_create("com.snake", DISPATCH_QUEUE_SERIAL);
        
        NSLog(@"this is mainQueue-0 %@", [NSThread currentThread]);
        dispatch_sync(serialQueue, ^{
            NSLog(@"1 %@", [NSThread currentThread]);
        });
        NSLog(@"this is mainQueue-1 %@", [NSThread currentThread]);
    
        dispatch_sync(serialQueue, ^{
            NSLog(@"2 %@", [NSThread currentThread]);
        });
    
        NSLog(@"this is mainQueue-2 %@", [NSThread currentThread]);
    }
    
    串行队列,同步任务

    结论:本来我预测的执行结果是

    this is mainQueue-0
    this is mainQueue-1
    this is mainQueue-2
    1
    2

    因为没有考虑到同步任务会阻塞当前线程。前面提到串行队列中的任务,按照FIFO的方式依次执行。但是如果考虑到阻塞的问题,后面的任务是没有进入队列的。

    串行队列 同步任务 嵌套

    串行队列,嵌套同步任务,阻塞当前线程,线程陷入死锁。
    既阻塞了当前线程、又想在当前线程末尾执行。

    串行队列嵌套任务 串行队列嵌套异步任务

    执行结果

    执行结果

    分析:嵌套内的同步任务会阻塞当前线程,并且陷入死锁。嵌套内的异步任务不会阻塞当前线程

    /**
     测试并行队列同步任务 嵌套
     */
    - (void)testSerialQueue {
        dispatch_queue_t serialQueue = dispatch_queue_create("com.snake", DISPATCH_QUEUE_CONCURRENT);
        
        NSLog(@"this is mainQueue-0 %@", [NSThread currentThread]);
        dispatch_sync(serialQueue, ^{
            NSLog(@"1 %@", [NSThread currentThread]);
            dispatch_sync(serialQueue, ^{
                NSLog(@"inside task %@", [NSThread currentThread]);
            });
        });
        NSLog(@"this is mainQueue-1 %@", [NSThread currentThread]);
    
        dispatch_sync(serialQueue, ^{
            NSLog(@"2 %@", [NSThread currentThread]);
            dispatch_sync(serialQueue, ^{
                NSLog(@"inside task 2 %@", [NSThread currentThread]);
            });
        });
    
        NSLog(@"this is mainQueue-2 %@", [NSThread currentThread]);
    }
    

    并行队列,同步任务

    测试并行队列同步任务的执行顺序
    • 并行队列的同步任务进行嵌套,有阻塞,不会产生死锁
    • 同步任务依次按顺序执行

    结论:

    串行队列,同步任务会阻塞当前线程,嵌套内的同步任务会产生死锁;

    参考:

    iOS 之GCD串行和并发队列的理解
    iOS基础深入补完计划--多线程(面试题)汇总

    相关文章

      网友评论

          本文标题:iOS GCD 串行和并发队列的理解

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