iOS开发的中的多线程 --- GCD

2018-11-12  本文已影响0人  jackli007

多线程实现的几种方案

技术方案 简介 语言 线程生命周期 使用频率
pthread 一套通用的多线程方案
适用于Linux、Unix、macOS等平台
跨平台/可移植,使用难度大
C 程序员管理 机会不用
NSThread 苹果封装,更加面向对象
简单使用,可直接操作线程对象
OC 程序员管理 偶尔使用
GCD 旨在替代NSThread多线程技术
充分利用设备的多核
C 自动管理 经常使用
NSOperation 基于GCD(底层GCD)
但比GCD多了一些更简单实用的功能
使用更加面向对象
OC 自动管理 经常使用

GCD的简介

GCD中有两个很重要的概念: 任务队列队列中存放的就是多个任务队列的执行,就是执行其存放的各个任务

任务:即操作,说白了就是一段代码块,在GCD中就是一个block,所以添加任务十分方便。任务有同步sync)和异步async)的区分。主要的区别在于会不会阻塞当前的线程。

队列:用于存放任务,决定任务是顺序执行的还是并发执行的。队列对应的有两种:串行队列并行队列

线程(thread)与队列(queue)的关系:线程队列是两个不同的概念。队列是用来存放任务的,而线程是由系统去创建和管理,而且一个线程中可能有多个串行并行队列。

创建队列

//获取主队列,即主线程
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_queue_create(const char *_Nullable label,
        dispatch_queue_attr_t _Nullable attr);

其中第一个参数是标识符,用于DEBUG时便于知道是哪个唯一的队列,可以为空。
第二个参数用来表示创建的队列是串行队列、还是并行队列
- DISPATCH_QUEUE_SERIAL或者NULL表示创建串行队列;
- DISPATCH_QUEUE_CONCURRENT表示创建的是并行队列。

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

创建任务

  dispatch_sync(<#queue#>, ^{
      //code here
      NSLog(@"同步任务");
  });
  dispatch_async(<#queue#>, ^{
      //code here
      NSLog(@"异步任务");
  });

组合代码测试

//主队列的任务(A)
- (void)syncAndMainQueue {
    //同步任务 + 主队列
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    NSLog(@"begin --- %@", [NSThread currentThread]);
    for (NSInteger index = 0 ; index < 10; index ++) {
        //同步任务(B)
        dispatch_sync(mainQueue, ^{
            NSLog(@"index : %ld --- %@", index , [NSThread currentThread]);
        });
    }
    NSLog(@"end --- %@", [NSThread currentThread]);
}

打印信息:

同步任务+主队列.png
结论:程序卡死,由于是同步任务(B),会阻塞当前线程,等待加入到线程的同步任务执行完成之后才会继续当前任务,而由于主队列是串行队列,会按按顺序(FIFO)执行队列中添加的任务,所以同步任何会等待正在执行的任务执行完毕,这样就造成了相互等待,继而造成死锁。
- (void)asyncAndMainQueue {
    //异步任务 + 主队列
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    NSLog(@"begin --- %@", [NSThread currentThread]);
    for (NSInteger index = 0 ; index < 10; index ++) {
        dispatch_async(mainQueue, ^{
            NSLog(@"index : %ld --- %@", index , [NSThread currentThread]);
        });
    }
    NSLog(@"end --- %@", [NSThread currentThread]);
}

打印信息:


异步任务 + 主队列.png

结论:在主线程串行执行。由于是异步任务,不会阻塞当前线程,由于主队列是串行队列,等待当前任务执行完成之后按顺序执行任务。

- (void)syncAndSerialQueue {
    //同步任务 + 串行队列
    dispatch_queue_t serailQueue = dispatch_queue_create("serialQueue", NULL);
    NSLog(@"begin --- %@", [NSThread currentThread]);
    for (NSInteger index = 0 ; index < 10; index ++) {
        dispatch_sync(serailQueue, ^{
            NSLog(@"index: %ld --- %@", index , [NSThread currentThread]);
        });
    }
    NSLog(@"end --- %@", [NSThread currentThread]);
}

打印:


同步任务 + 串行队列.png

结论:没有开启新线程,在当前线程执行该同步任务。由于是同步任务,会阻塞当前线程,而队列是串行队列,会按顺序执行任务,等到该队列中的所有任务执行完毕之后,当前线程才会继续执行下去。

- (void)asyncAndSerialQueue {
    //异步任务 + 串行队列
    dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", NULL);
    NSLog(@"begin --- %@", [NSThread currentThread]);
    for (NSInteger index = 0; index < 10; index ++) {
        dispatch_async(serialQueue, ^{
            NSLog(@"index: %ld --- %@", index , [NSThread currentThread]);
        });
    }
    NSLog(@"end --- %@", [NSThread currentThread]);
}

打印:


异步任务 + 串行队列.png

结论:由于是异步任务,不会阻塞当前线程,开了新线程,由于是串行队列,会按顺序执行任务,所以只需开启一条新的线程。

- (void)syncAndConcurrent {
    //同步任务 + 并行队列
    dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
    NSLog(@"begin --- %@", [NSThread currentThread]);
    for (NSInteger index = 0; index < 10; index ++) {
        dispatch_sync(concurrentQueue, ^{
            NSLog(@"index: %ld --- %@", index , [NSThread currentThread]);
        });
    }
    NSLog(@"end --- %@", [NSThread currentThread]);    
}

打印:


同步任务 + 并行队列.png

结论:由于是同步任务,会阻塞当前线程,且不会开启新线程,所以同步任务会在当前线程执行完毕,等到完毕之后,当前线程执行执行。

- (void)asyncAndConcurrent {
    //异步任务 + 并行队列
    dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
    NSLog(@"begin --- %@", [NSThread currentThread]);
    for (NSInteger index = 0; index < 10; index ++) {
        dispatch_async(concurrentQueue, ^{
            NSLog(@"index: %ld --- %@", index, [NSThread currentThread]);
        });
    }
    NSLog(@"end --- %@", [NSThread currentThread]);
}

打印


异步任务 + 并行队列.png

结论:由于是异步任务,不会阻塞当前线程,同时会开启新的线程,而且由于队列是并行队列,会开启多条线程,并发的执行这些异步任务。

总结

同步(sync) 异步(async)
串行队列 当前线程,顺序执行 其他线程,顺序执行
并行队列 当前线程,顺序执行 开多个线程,并发执行
主队列 程序死锁 主队列,顺序执行
上一篇 下一篇

猜你喜欢

热点阅读