iOS 多线程(GCD使用指南)

389 阅读39分钟

什么是GCD

Grand Central Dispatch (GCD) 是 Apple 开发的一个多核编程的解决方法。该方法在 Mac OS X 10.6 雪豹中首次推出,并随后被引入到了 iOS4.0 中。GCD 是一个替代诸如 NSThread, NSOperationQueue, NSInvocationOperation 等技术的很高效和强大的技术。它为你提供了很多底层工具(比如队列和信号量),你可以组合这些工具来实现自己想要的多线程效果。

GCD API列表

API 说明
dispatch_sync() 同步执行
dispatch_async() 异步执行
dispatch_after() 延时执行
dispatch_once() 一次性执行
dispatch_apply() 提交队列
dispatch_queue_create() 创建队列
dispatch_group_create() 创建队列组
dispatch_group_enter() / dispatch_group_leave() 将队列组中的任务未执行完毕的任务数目加减1(两个函数要配合使用)
dispatch_group_notify() 监听队列组执行完毕
dispatch_group_wait() 设置等待时间(返回 0成功,1失败)
dispatch_semaphore_creat() 创建信号量
dispatch_barrier_sync() 同步栅栏函数
dispatch_barrier_async() 异步栅栏函数

GCD中的队列

Dispatch Queue
Dispatch Queue是用来执行任务的队列,是GCD中最基本的元素之一。图示:


一张图片可以很直观地描述GCD与线程之间的关系:
两种Dispatch Queue

Dispatch Queue种类 说明
Serial Dispatch Queue(串行队列) 等待现在执行中处理结束
Concurrent Dispatch Queue(并发队列) 不等待现在执行中处理
  • Serial Dispatch Queue(串行队列): 假设把 任务1 任务2 任务3 任务4 四个任务依次加入到一个Serial Dispatch Queue中,这个Serial Dispatch Queue会创建一个线程,依次执行这四个任务。
  • Concurrent Dispatch Queue(并发队列): 假设把 任务1 任务2 任务3 任务4 四个任务依次加入到一个Concurrent Dispatch Queue中,这个Concurrent Dispatch Queue会创建多个线程,并发执行这四个任务。
  • 图示:

Main Dispatch Queue(主队列)
是在主线程执行的dispatch queue, Main Dispatch Queue(主队列)是一个Serail Dispatch Queue(串行队列)。追加到Main Dispatch Queue(主队列)的处理在主线程的RunLoop中执行。一般将用户界面更新等必需要在主线程中执行的处理追加到Main Dispatch Queue(主队列)中。

名称 Dispatch Queue的种类 说明
Main Dispatch Queue Serial Dispatch Queue 主线程执行

获取Main Dispatch Queue方法:

dispatch_queue_t mainDispatchQueue = dispatch_get_main_queue();

Global Dispatch Queue(全局并发队列)
是所有应用程序都能过使用的Concurrent Dispatch Queue(全局并发队列)。没有必要通过dispatch_queue_create函数逐个创建Concurrent Dispatch Queue(并发队列),只要获取Global Dispatch Queue(全局并发队列)使用即可。Global Dispatch Queue(全局并发队列)有四个优先级

名称 Dispatch Queue的种类 说明
Global Dispatch Queue(High Priority) Concurrent Dispatch queue 执行优先级:高(最高)
Global Dispatch Queue(Default Priority) Concurrent Dispatch queue 执行优先级:默认
Global Dispatch Queue(Low Priority) Concurrent Dispatch queue 执行优先级:低
Global Dispatch Queue(Background Priority) Concurrent Dispatch queue 执行优先级:后台

获取Global Dispatch Queue方法:

dispatch_queue_t globalDispatchQueueHigh = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);

dispatch_queue_t globalDispatchQueueDefault = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_queue_t globalDispatchQueueLow = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);

dispatch_queue_t globalDispatchQueueBackground = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);

Main Dispatch QueueGlobal Dispatch Queue的搭配使用

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    /**
     *  可并行处理的任务TODO
     */

    dispatch_async(dispatch_get_main_queue(), ^{
        /**
         *  主线程执行
         */
    });
});

GCD中队列与线程的搭配使用情况

  • 同步函数_串行队列

(不会开启新线程,串行执行任务)

  • 同步函数_并发队列

(不会开启新线程,并发执行任务失效!)

  • 异步函数_串行队列

(开启新线程,串行执行任务)

  • 异步函数_并发队列

(开启新线程,并发执行任务)

GCD实例代码

  • 最基础的写法
//1:创建串行队列
dispatch_queue_t queue = dispatch_queue_create("Noah", DISPATCH_QUEUE_SERIAL);
//2:创建任务
dispatch_block_t taskBlock = ^{
    NSLog(@"%@",[NSThread currentThread]);
};
//3:利用函数把任务放入队列
dispatch_sync(queue, taskBlock);
  • 主队列同步函数
/**
 主队列同步
 不会开线程
 */
- (void)mainSyncTest{
    
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        
        for (int i = 0; i<20; i++) {
            dispatch_sync(dispatch_get_main_queue(), ^{
                NSLog(@"%d-%@",i,[NSThread currentThread]);
            });
        }
    });

    NSLog(@"hello queue");
}

// 打印
2020-01-27 17:26:23.840677+0800 001---函数与队列[1750:96869] hello queue
2020-01-27 17:26:23.847367+0800 001---函数与队列[1750:96869] 0-<NSThread: 0x6000027dd3c0>{number = 1, name = main}
2020-01-27 17:26:23.847781+0800 001---函数与队列[1750:96869] 1-<NSThread: 0x6000027dd3c0>{number = 1, name = main}
2020-01-27 17:26:23.848094+0800 001---函数与队列[1750:96869] 2-<NSThread: 0x6000027dd3c0>{number = 1, name = main}
2020-01-27 17:26:23.848183+0800 001---函数与队列[1750:96869] 3-<NSThread: 0x6000027dd3c0>{number = 1, name = main}
2020-01-27 17:26:23.848259+0800 001---函数与队列[1750:96869] 4-<NSThread: 0x6000027dd3c0>{number = 1, name = main}
2020-01-27 17:26:23.848649+0800 001---函数与队列[1750:96869] 5-<NSThread: 0x6000027dd3c0>{number = 1, name = main}
2020-01-27 17:26:23.848740+0800 001---函数与队列[1750:96869] 6-<NSThread: 0x6000027dd3c0>{number = 1, name = main}
2020-01-27 17:26:23.848926+0800 001---函数与队列[1750:96869] 7-<NSThread: 0x6000027dd3c0>{number = 1, name = main}
2020-01-27 17:26:23.849003+0800 001---函数与队列[1750:96869] 8-<NSThread: 0x6000027dd3c0>{number = 1, name = main}
2020-01-27 17:26:23.849208+0800 001---函数与队列[1750:96869] 9-<NSThread: 0x6000027dd3c0>{number = 1, name = main}
2020-01-27 17:26:23.852510+0800 001---函数与队列[1750:96869] 10-<NSThread: 0x6000027dd3c0>{number = 1, name = main}
2020-01-27 17:26:23.852617+0800 001---函数与队列[1750:96869] 11-<NSThread: 0x6000027dd3c0>{number = 1, name = main}
2020-01-27 17:26:23.852688+0800 001---函数与队列[1750:96869] 12-<NSThread: 0x6000027dd3c0>{number = 1, name = main}
2020-01-27 17:26:23.852774+0800 001---函数与队列[1750:96869] 13-<NSThread: 0x6000027dd3c0>{number = 1, name = main}
2020-01-27 17:26:23.852859+0800 001---函数与队列[1750:96869] 14-<NSThread: 0x6000027dd3c0>{number = 1, name = main}
2020-01-27 17:26:23.852947+0800 001---函数与队列[1750:96869] 15-<NSThread: 0x6000027dd3c0>{number = 1, name = main}
2020-01-27 17:26:23.853023+0800 001---函数与队列[1750:96869] 16-<NSThread: 0x6000027dd3c0>{number = 1, name = main}
2020-01-27 17:26:23.853092+0800 001---函数与队列[1750:96869] 17-<NSThread: 0x6000027dd3c0>{number = 1, name = main}
2020-01-27 17:26:23.853186+0800 001---函数与队列[1750:96869] 18-<NSThread: 0x6000027dd3c0>{number = 1, name = main}
2020-01-27 17:26:23.853265+0800 001---函数与队列[1750:96869] 19-<NSThread: 0x6000027dd3c0>{number = 1, name = main}
  • 主队列异步函数
/**
 主队列异步
 不会开线程 顺序
 */
- (void)mainAsyncTest{
    for (int i = 0; i<20; i++) {
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"%d-%@",i,[NSThread currentThread]);
        });
    }
    NSLog(@"hello queue");
}

// 打印
2020-01-27 17:30:43.639916+0800 001---函数与队列[1775:98841] hello queue
2020-01-27 17:30:43.646298+0800 001---函数与队列[1775:98841] 0-<NSThread: 0x600003aea900>{number = 1, name = main}
2020-01-27 17:30:43.646410+0800 001---函数与队列[1775:98841] 1-<NSThread: 0x600003aea900>{number = 1, name = main}
2020-01-27 17:30:43.646486+0800 001---函数与队列[1775:98841] 2-<NSThread: 0x600003aea900>{number = 1, name = main}
2020-01-27 17:30:43.646554+0800 001---函数与队列[1775:98841] 3-<NSThread: 0x600003aea900>{number = 1, name = main}
2020-01-27 17:30:43.646638+0800 001---函数与队列[1775:98841] 4-<NSThread: 0x600003aea900>{number = 1, name = main}
2020-01-27 17:30:43.646706+0800 001---函数与队列[1775:98841] 5-<NSThread: 0x600003aea900>{number = 1, name = main}
2020-01-27 17:30:43.646768+0800 001---函数与队列[1775:98841] 6-<NSThread: 0x600003aea900>{number = 1, name = main}
2020-01-27 17:30:43.646842+0800 001---函数与队列[1775:98841] 7-<NSThread: 0x600003aea900>{number = 1, name = main}
2020-01-27 17:30:43.646907+0800 001---函数与队列[1775:98841] 8-<NSThread: 0x600003aea900>{number = 1, name = main}
2020-01-27 17:30:43.646982+0800 001---函数与队列[1775:98841] 9-<NSThread: 0x600003aea900>{number = 1, name = main}
2020-01-27 17:30:43.647046+0800 001---函数与队列[1775:98841] 10-<NSThread: 0x600003aea900>{number = 1, name = main}
2020-01-27 17:30:43.647144+0800 001---函数与队列[1775:98841] 11-<NSThread: 0x600003aea900>{number = 1, name = main}
2020-01-27 17:30:43.647326+0800 001---函数与队列[1775:98841] 12-<NSThread: 0x600003aea900>{number = 1, name = main}
2020-01-27 17:30:43.647526+0800 001---函数与队列[1775:98841] 13-<NSThread: 0x600003aea900>{number = 1, name = main}
2020-01-27 17:30:43.647701+0800 001---函数与队列[1775:98841] 14-<NSThread: 0x600003aea900>{number = 1, name = main}
2020-01-27 17:30:43.647876+0800 001---函数与队列[1775:98841] 15-<NSThread: 0x600003aea900>{number = 1, name = main}
2020-01-27 17:30:43.648045+0800 001---函数与队列[1775:98841] 16-<NSThread: 0x600003aea900>{number = 1, name = main}
2020-01-27 17:30:43.648204+0800 001---函数与队列[1775:98841] 17-<NSThread: 0x600003aea900>{number = 1, name = main}
2020-01-27 17:30:43.648363+0800 001---函数与队列[1775:98841] 18-<NSThread: 0x600003aea900>{number = 1, name = main}
2020-01-27 17:30:43.648511+0800 001---函数与队列[1775:98841] 19-<NSThread: 0x600003aea900>{number = 1, name = main}
  • 全局队列异步函数
/**
 全局异步
 全局队列:一个并发队列
 */
- (void)globalAsyncTest{
    for (int i = 0; i<20; i++) {
        
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            NSLog(@"%d-%@",i,[NSThread currentThread]);
        });
    }
    
    NSLog(@"hello queue");
}

// 打印
2020-01-27 17:32:46.849803+0800 001---函数与队列[1796:100014] hello queue
2020-01-27 17:32:46.849839+0800 001---函数与队列[1796:100060] 0-<NSThread: 0x60000004db40>{number = 3, name = (null)}
2020-01-27 17:32:46.849841+0800 001---函数与队列[1796:100073] 1-<NSThread: 0x600000017400>{number = 4, name = (null)}
2020-01-27 17:32:46.849872+0800 001---函数与队列[1796:100061] 2-<NSThread: 0x60000004db00>{number = 5, name = (null)}
2020-01-27 17:32:46.849880+0800 001---函数与队列[1796:100059] 3-<NSThread: 0x60000005fb00>{number = 6, name = (null)}
2020-01-27 17:32:46.849917+0800 001---函数与队列[1796:100073] 6-<NSThread: 0x600000017400>{number = 4, name = (null)}
2020-01-27 17:32:46.849924+0800 001---函数与队列[1796:100060] 7-<NSThread: 0x60000004db40>{number = 3, name = (null)}
2020-01-27 17:32:46.849928+0800 001---函数与队列[1796:100058] 4-<NSThread: 0x600000074700>{number = 7, name = (null)}
2020-01-27 17:32:46.849950+0800 001---函数与队列[1796:100061] 9-<NSThread: 0x60000004db00>{number = 5, name = (null)}
2020-01-27 17:32:46.849964+0800 001---函数与队列[1796:100074] 5-<NSThread: 0x60000007c600>{number = 8, name = (null)}
2020-01-27 17:32:46.849974+0800 001---函数与队列[1796:100059] 10-<NSThread: 0x60000005fb00>{number = 6, name = (null)}
2020-01-27 17:32:46.850015+0800 001---函数与队列[1796:100075] 8-<NSThread: 0x600000064040>{number = 9, name = (null)}
2020-01-27 17:32:46.850033+0800 001---函数与队列[1796:100076] 11-<NSThread: 0x600000078280>{number = 10, name = (null)}
2020-01-27 17:32:46.850021+0800 001---函数与队列[1796:100073] 12-<NSThread: 0x600000017400>{number = 4, name = (null)}
2020-01-27 17:32:46.850065+0800 001---函数与队列[1796:100077] 13-<NSThread: 0x600000070340>{number = 11, name = (null)}
2020-01-27 17:32:46.850068+0800 001---函数与队列[1796:100078] 15-<NSThread: 0x60000004dec0>{number = 12, name = (null)}
2020-01-27 17:32:46.850096+0800 001---函数与队列[1796:100061] 17-<NSThread: 0x60000004db00>{number = 5, name = (null)}
2020-01-27 17:32:46.850107+0800 001---函数与队列[1796:100079] 16-<NSThread: 0x60000005fe00>{number = 13, name = (null)}
2020-01-27 17:32:46.850021+0800 001---函数与队列[1796:100060] 14-<NSThread: 0x60000004db40>{number = 3, name = (null)}
2020-01-27 17:32:46.850138+0800 001---函数与队列[1796:100080] 18-<NSThread: 0x600000078340>{number = 14, name = (null)}
2020-01-27 17:32:46.850161+0800 001---函数与队列[1796:100081] 19-<NSThread: 0x6000000640c0>{number = 15, name = (null)}
  • 全局队列同步函数
/**
 全局同步
 全局队列:一个并发队列
 */
- (void)globalSyncTest{
    for (int i = 0; i<20; i++) {
        dispatch_sync(dispatch_get_global_queue(0, 0), ^{
            NSLog(@"%d-%@",i,[NSThread currentThread]);
        });
    }
    
    NSLog(@"hello queue");
}

// 打印
2020-01-27 17:34:19.755161+0800 001---函数与队列[1825:101279] 0-<NSThread: 0x600003aa93c0>{number = 1, name = main}
2020-01-27 17:34:19.755253+0800 001---函数与队列[1825:101279] 1-<NSThread: 0x600003aa93c0>{number = 1, name = main}
2020-01-27 17:34:19.755328+0800 001---函数与队列[1825:101279] 2-<NSThread: 0x600003aa93c0>{number = 1, name = main}
2020-01-27 17:34:19.755422+0800 001---函数与队列[1825:101279] 3-<NSThread: 0x600003aa93c0>{number = 1, name = main}
2020-01-27 17:34:19.755485+0800 001---函数与队列[1825:101279] 4-<NSThread: 0x600003aa93c0>{number = 1, name = main}
2020-01-27 17:34:19.755555+0800 001---函数与队列[1825:101279] 5-<NSThread: 0x600003aa93c0>{number = 1, name = main}
2020-01-27 17:34:19.755619+0800 001---函数与队列[1825:101279] 6-<NSThread: 0x600003aa93c0>{number = 1, name = main}
2020-01-27 17:34:19.755695+0800 001---函数与队列[1825:101279] 7-<NSThread: 0x600003aa93c0>{number = 1, name = main}
2020-01-27 17:34:19.755760+0800 001---函数与队列[1825:101279] 8-<NSThread: 0x600003aa93c0>{number = 1, name = main}
2020-01-27 17:34:19.755825+0800 001---函数与队列[1825:101279] 9-<NSThread: 0x600003aa93c0>{number = 1, name = main}
2020-01-27 17:34:19.755887+0800 001---函数与队列[1825:101279] 10-<NSThread: 0x600003aa93c0>{number = 1, name = main}
2020-01-27 17:34:19.755949+0800 001---函数与队列[1825:101279] 11-<NSThread: 0x600003aa93c0>{number = 1, name = main}
2020-01-27 17:34:19.763221+0800 001---函数与队列[1825:101279] 12-<NSThread: 0x600003aa93c0>{number = 1, name = main}
2020-01-27 17:34:19.763318+0800 001---函数与队列[1825:101279] 13-<NSThread: 0x600003aa93c0>{number = 1, name = main}
2020-01-27 17:34:19.763412+0800 001---函数与队列[1825:101279] 14-<NSThread: 0x600003aa93c0>{number = 1, name = main}
2020-01-27 17:34:19.763468+0800 001---函数与队列[1825:101279] 15-<NSThread: 0x600003aa93c0>{number = 1, name = main}
2020-01-27 17:34:19.763553+0800 001---函数与队列[1825:101279] 16-<NSThread: 0x600003aa93c0>{number = 1, name = main}
2020-01-27 17:34:19.763615+0800 001---函数与队列[1825:101279] 17-<NSThread: 0x600003aa93c0>{number = 1, name = main}
2020-01-27 17:34:19.763681+0800 001---函数与队列[1825:101279] 18-<NSThread: 0x600003aa93c0>{number = 1, name = main}
2020-01-27 17:34:19.763744+0800 001---函数与队列[1825:101279] 19-<NSThread: 0x600003aa93c0>{number = 1, name = main}
2020-01-27 17:34:19.763795+0800 001---函数与队列[1825:101279] hello queue
  • 同步队列并发函数
/**
 同步并发
 不开线程:就算并发出来,没有坑位接受,所以顺序执行
 */
- (void)concurrentSyncTest{

    //1:创建并发队列
    dispatch_queue_t queue = dispatch_queue_create("Noah", DISPATCH_QUEUE_CONCURRENT);
    for (int i = 0; i<20; i++) {
        dispatch_sync(queue, ^{
            NSLog(@"%d-%@",i,[NSThread currentThread]);
        });
    }
    
    NSLog(@"hello queue");
}

// 打印
2020-01-27 17:36:47.811986+0800 001---函数与队列[1846:102561] 0-<NSThread: 0x600000cd93c0>{number = 1, name = main}
2020-01-27 17:36:47.812081+0800 001---函数与队列[1846:102561] 1-<NSThread: 0x600000cd93c0>{number = 1, name = main}
2020-01-27 17:36:47.812152+0800 001---函数与队列[1846:102561] 2-<NSThread: 0x600000cd93c0>{number = 1, name = main}
2020-01-27 17:36:47.812213+0800 001---函数与队列[1846:102561] 3-<NSThread: 0x600000cd93c0>{number = 1, name = main}
2020-01-27 17:36:47.812280+0800 001---函数与队列[1846:102561] 4-<NSThread: 0x600000cd93c0>{number = 1, name = main}
2020-01-27 17:36:47.812340+0800 001---函数与队列[1846:102561] 5-<NSThread: 0x600000cd93c0>{number = 1, name = main}
2020-01-27 17:36:47.812396+0800 001---函数与队列[1846:102561] 6-<NSThread: 0x600000cd93c0>{number = 1, name = main}
2020-01-27 17:36:47.812456+0800 001---函数与队列[1846:102561] 7-<NSThread: 0x600000cd93c0>{number = 1, name = main}
2020-01-27 17:36:47.812526+0800 001---函数与队列[1846:102561] 8-<NSThread: 0x600000cd93c0>{number = 1, name = main}
2020-01-27 17:36:47.812588+0800 001---函数与队列[1846:102561] 9-<NSThread: 0x600000cd93c0>{number = 1, name = main}
2020-01-27 17:36:47.812649+0800 001---函数与队列[1846:102561] 10-<NSThread: 0x600000cd93c0>{number = 1, name = main}
2020-01-27 17:36:47.812728+0800 001---函数与队列[1846:102561] 11-<NSThread: 0x600000cd93c0>{number = 1, name = main}
2020-01-27 17:36:47.820467+0800 001---函数与队列[1846:102561] 12-<NSThread: 0x600000cd93c0>{number = 1, name = main}
2020-01-27 17:36:47.820589+0800 001---函数与队列[1846:102561] 13-<NSThread: 0x600000cd93c0>{number = 1, name = main}
2020-01-27 17:36:47.820703+0800 001---函数与队列[1846:102561] 14-<NSThread: 0x600000cd93c0>{number = 1, name = main}
2020-01-27 17:36:47.820774+0800 001---函数与队列[1846:102561] 15-<NSThread: 0x600000cd93c0>{number = 1, name = main}
2020-01-27 17:36:47.820867+0800 001---函数与队列[1846:102561] 16-<NSThread: 0x600000cd93c0>{number = 1, name = main}
2020-01-27 17:36:47.820949+0800 001---函数与队列[1846:102561] 17-<NSThread: 0x600000cd93c0>{number = 1, name = main}
2020-01-27 17:36:47.821044+0800 001---函数与队列[1846:102561] 18-<NSThread: 0x600000cd93c0>{number = 1, name = main}
2020-01-27 17:36:47.821108+0800 001---函数与队列[1846:102561] 19-<NSThread: 0x600000cd93c0>{number = 1, name = main}
2020-01-27 17:36:47.821180+0800 001---函数与队列[1846:102561] hello queue
  • 异步队列并发函数
/**
 异步并发
 一次多个 没有顺序
 开线程
 */
- (void)concurrentAsyncTest{
    //1:创建并发队列
    dispatch_queue_t queue = dispatch_queue_create("Noah", DISPATCH_QUEUE_CONCURRENT);
    for (int i = 0; i<20; i++) {
        dispatch_async(queue, ^{
            NSLog(@"%d-%@",i,[NSThread currentThread]);
        });
    }
    
    NSLog(@"hello queue");
    
}

// 打印
2020-01-27 17:44:03.551880+0800 001---函数与队列[1878:104767] hello queue
2020-01-27 17:44:03.551943+0800 001---函数与队列[1878:104812] 0-<NSThread: 0x6000005797c0>{number = 3, name = (null)}
2020-01-27 17:44:03.551945+0800 001---函数与队列[1878:104814] 3-<NSThread: 0x6000005695c0>{number = 6, name = (null)}
2020-01-27 17:44:03.551950+0800 001---函数与队列[1878:104813] 1-<NSThread: 0x60000050afc0>{number = 4, name = (null)}
2020-01-27 17:44:03.551951+0800 001---函数与队列[1878:104825] 4-<NSThread: 0x600000543a00>{number = 7, name = (null)}
2020-01-27 17:44:03.551951+0800 001---函数与队列[1878:104815] 2-<NSThread: 0x600000543a80>{number = 5, name = (null)}
2020-01-27 17:44:03.551984+0800 001---函数与队列[1878:104826] 5-<NSThread: 0x60000050af40>{number = 8, name = (null)}
2020-01-27 17:44:03.552022+0800 001---函数与队列[1878:104812] 8-<NSThread: 0x6000005797c0>{number = 3, name = (null)}
2020-01-27 17:44:03.552033+0800 001---函数与队列[1878:104814] 9-<NSThread: 0x6000005695c0>{number = 6, name = (null)}
2020-01-27 17:44:03.552038+0800 001---\345\2072020-01-27 17:44:03.552075+0800 001---函数与队列[1878:104829] 10-<NSThread: 0x60000050af80>{number = 11, name = (null)}
2020-01-27 17:44:03.552083+0800 001---函数与队列[1878:104828] 7-<NSThread: 0x600000564340>{number = 10, name = (null)}
2020-01-27 17:44:03.552093+0800 001---函数与队列[1878:104826] 15-<NSThread: 0x60000050af40>{number = 8, name = (null)}
2020-01-27 17:44:03.552093+0800 001---函数与队列[1878:104815] 13-<NSThread: 0x600000543a80>{number = 5, name = (null)}
2020-01-27 17:44:03.552198+0800 001---函数与队列[1878:104834] 19-<NSThread: 0x600000575540>{number = 16, name = (null)}
2020-01-27 17:44:03.552113+0800 001---函数与队列[1878:104830] 14-<NSThread: 0x60000054c6c0>{number = 12, name = (null)}
2020-01-27 17:44:03.552135+0800 001---函数与队列[1878:104831] 16-<NSThread: 0x6000005643c0>{number = 13, name = (null)}
2020-01-27 17:44:03.552150+0800 001---函数与队列[1878:104832] 17-<NSThread: 0x600000569a00>{number = 14, name = (null)}
2020-01-27 17:44:03.552179+0800 001---函数与队列[1878:104833] 18-<NSThread: 0x600000543d80>{number = 15, name = (null)}
\275数与队列[1878:104827] 6-<NSThread: 0x60000054c640>{number = 9, name = (null)}
2020-01-27 17:44:03.552061+0800 001---函数与队列[1878:104813] 11-<NSThread: 0x60000050afc0>{number = 4, name = (null)}
2020-01-27 17:44:03.552063+0800 001---函数与队列[1878:104825] 12-<NSThread: 0x600000543a00>{number = 7, name = (null)}
  • 串行队列异步函数
/**
 串行异步队列
 1:异步执行:会开启线程,顺序跟着耗时走
 */
- (void)serialAsyncTest{
    //1:创建串行队列
    dispatch_queue_t queue = dispatch_queue_create("Noah", DISPATCH_QUEUE_SERIAL);
    for (int i = 0; i<20; i++) {
        dispatch_async(queue, ^{
            NSLog(@"%d-%@",i,[NSThread currentThread]);
        });
    }
    
    NSLog(@"hello queue");
    
}
// 打印
2020-01-27 17:47:12.046872+0800 001---函数与队列[1896:106036] hello queue
2020-01-27 17:47:12.046903+0800 001---函数与队列[1896:106075] 0-<NSThread: 0x600003450900>{number = 3, name = (null)}
2020-01-27 17:47:12.046981+0800 001---函数与队列[1896:106075] 1-<NSThread: 0x600003450900>{number = 3, name = (null)}
2020-01-27 17:47:12.047066+0800 001---函数与队列[1896:106075] 2-<NSThread: 0x600003450900>{number = 3, name = (null)}
2020-01-27 17:47:12.047141+0800 001---函数与队列[1896:106075] 3-<NSThread: 0x600003450900>{number = 3, name = (null)}
2020-01-27 17:47:12.047218+0800 001---函数与队列[1896:106075] 4-<NSThread: 0x600003450900>{number = 3, name = (null)}
2020-01-27 17:47:12.047319+0800 001---函数与队列[1896:106075] 5-<NSThread: 0x600003450900>{number = 3, name = (null)}
2020-01-27 17:47:12.047390+0800 001---函数与队列[1896:106075] 6-<NSThread: 0x600003450900>{number = 3, name = (null)}
2020-01-27 17:47:12.047531+0800 001---函数与队列[1896:106075] 7-<NSThread: 0x600003450900>{number = 3, name = (null)}
2020-01-27 17:47:12.047612+0800 001---函数与队列[1896:106075] 8-<NSThread: 0x600003450900>{number = 3, name = (null)}
2020-01-27 17:47:12.047705+0800 001---函数与队列[1896:106075] 9-<NSThread: 0x600003450900>{number = 3, name = (null)}
2020-01-27 17:47:12.047799+0800 001---函数与队列[1896:106075] 10-<NSThread: 0x600003450900>{number = 3, name = (null)}
2020-01-27 17:47:12.047876+0800 001---函数与队列[1896:106075] 11-<NSThread: 0x600003450900>{number = 3, name = (null)}
2020-01-27 17:47:12.056948+0800 001---函数与队列[1896:106075] 12-<NSThread: 0x600003450900>{number = 3, name = (null)}
2020-01-27 17:47:12.057028+0800 001---函数与队列[1896:106075] 13-<NSThread: 0x600003450900>{number = 3, name = (null)}
2020-01-27 17:47:12.057104+0800 001---函数与队列[1896:106075] 14-<NSThread: 0x600003450900>{number = 3, name = (null)}
2020-01-27 17:47:12.057165+0800 001---函数与队列[1896:106075] 15-<NSThread: 0x600003450900>{number = 3, name = (null)}
2020-01-27 17:47:12.057237+0800 001---函数与队列[1896:106075] 16-<NSThread: 0x600003450900>{number = 3, name = (null)}
2020-01-27 17:47:12.057312+0800 001---函数与队列[1896:106075] 17-<NSThread: 0x600003450900>{number = 3, name = (null)}
2020-01-27 17:47:12.057394+0800 001---函数与队列[1896:106075] 18-<NSThread: 0x600003450900>{number = 3, name = (null)}
2020-01-27 17:47:12.057469+0800 001---函数与队列[1896:106075] 19-<NSThread: 0x600003450900>{number = 3, name = (null)}
  • 串行队列同步函数
/**
 串行同步队列
 1:同步执行:一行一行代码从上向下执行,当前代码不执行完成,不会执行后续代码 同步不会开启线程
 2:串行队列:一个一个的调度任务,前一个任务没有执行完成,不会调度后面的任务
 */
- (void)serialSyncTest{
    //1:创建串行队列
    dispatch_queue_t queue = dispatch_queue_create("Noah", DISPATCH_QUEUE_SERIAL);
    for (int i = 0; i<20; i++) {
        dispatch_sync(queue, ^{
            NSLog(@"%d-%@",i,[NSThread currentThread]);
        });
    }
    
    NSLog(@"hello queue");

}

// 打印
2020-01-27 17:48:54.224033+0800 001---函数与队列[1920:107306] 0-<NSThread: 0x6000012ae940>{number = 1, name = main}
2020-01-27 17:48:54.224142+0800 001---函数与队列[1920:107306] 1-<NSThread: 0x6000012ae940>{number = 1, name = main}
2020-01-27 17:48:54.224214+0800 001---函数与队列[1920:107306] 2-<NSThread: 0x6000012ae940>{number = 1, name = main}
2020-01-27 17:48:54.224270+0800 001---函数与队列[1920:107306] 3-<NSThread: 0x6000012ae940>{number = 1, name = main}
2020-01-27 17:48:54.224340+0800 001---函数与队列[1920:107306] 4-<NSThread: 0x6000012ae940>{number = 1, name = main}
2020-01-27 17:48:54.224398+0800 001---函数与队列[1920:107306] 5-<NSThread: 0x6000012ae940>{number = 1, name = main}
2020-01-27 17:48:54.224460+0800 001---函数与队列[1920:107306] 6-<NSThread: 0x6000012ae940>{number = 1, name = main}
2020-01-27 17:48:54.224515+0800 001---函数与队列[1920:107306] 7-<NSThread: 0x6000012ae940>{number = 1, name = main}
2020-01-27 17:48:54.224583+0800 001---函数与队列[1920:107306] 8-<NSThread: 0x6000012ae940>{number = 1, name = main}
2020-01-27 17:48:54.224644+0800 001---函数与队列[1920:107306] 9-<NSThread: 0x6000012ae940>{number = 1, name = main}
2020-01-27 17:48:54.224712+0800 001---函数与队列[1920:107306] 10-<NSThread: 0x6000012ae940>{number = 1, name = main}
2020-01-27 17:48:54.224774+0800 001---函数与队列[1920:107306] 11-<NSThread: 0x6000012ae940>{number = 1, name = main}
2020-01-27 17:48:54.224833+0800 001---函数与队列[1920:107306] 12-<NSThread: 0x6000012ae940>{number = 1, name = main}
2020-01-27 17:48:54.232531+0800 001---函数与队列[1920:107306] 13-<NSThread: 0x6000012ae940>{number = 1, name = main}
2020-01-27 17:48:54.232614+0800 001---函数与队列[1920:107306] 14-<NSThread: 0x6000012ae940>{number = 1, name = main}
2020-01-27 17:48:54.232682+0800 001---函数与队列[1920:107306] 15-<NSThread: 0x6000012ae940>{number = 1, name = main}
2020-01-27 17:48:54.232741+0800 001---函数与队列[1920:107306] 16-<NSThread: 0x6000012ae940>{number = 1, name = main}
2020-01-27 17:48:54.232820+0800 001---函数与队列[1920:107306] 17-<NSThread: 0x6000012ae940>{number = 1, name = main}
2020-01-27 17:48:54.232890+0800 001---函数与队列[1920:107306] 18-<NSThread: 0x6000012ae940>{number = 1, name = main}
2020-01-27 17:48:54.232948+0800 001---函数与队列[1920:107306] 19-<NSThread: 0x6000012ae940>{number = 1, name = main}
2020-01-27 17:48:54.233001+0800 001---函数与队列[1920:107306] hello queue
  • dispatch_after使用
/**
 延迟测试
 */
- (void)delayDemo{
    
    //NSEC_PER_SEC : 1000000000ull 纳秒每秒 0.0000001 可以这么做参数
    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC));
    //串行队列来测试 延迟的方法是不是异步的!
    dispatch_queue_t queue = dispatch_queue_create("com.lg.cn", DISPATCH_QUEUE_SERIAL);
    dispatch_after(time, queue, ^{
        NSLog(@"延迟打印");
    });
    NSLog(@"打印完了?");
}

//打印
2020-01-27 19:38:24.727940+0800 005---GCD进阶使用(下)[2216:130497] 打印完了?
2020-01-27 19:38:25.816560+0800 005---GCD进阶使用(下)[2216:130584] 延迟打印
  • dispatch_once使用
/**
 单例
 */
+(instancetype)shareManager{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self alloc] init];
    });
    return instance;
}
  • dispatch_group_async使用
/**
 调度组测试
 */
- (void)groupDemo{
    
    //创建调度组
    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_queue_t queue1 = dispatch_queue_create("com.nh.cn", DISPATCH_QUEUE_CONCURRENT);

    // SIGNAL
    dispatch_group_async(group, queue, ^{
        NSString *logoStr = @"https://dss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo_top-e3b63a0b1b.png";
        NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:logoStr]];
        UIImage *image = [UIImage imageWithData:data];
        [self.mArray addObject:image];
    });
    
    dispatch_group_async(group, queue1, ^{

        // afn --- sdk : queue: com.afn.cn
        NSString *logoStr = @"https://dss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo_top-e3b63a0b1b.png";
        NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:logoStr]];
        UIImage *image = [UIImage imageWithData:data];
        [self.mArray addObject:image];

    });
    
    
    __block UIImage *newImage = nil;
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"数组个数:%ld",self.mArray.count);
    });

}

// 打印
2020-01-27 20:24:30.544956+0800 005---GCD进阶使用(下)[2546:203237] 数组个数:2
  • 调度组内部方法使用
/**
 调度组内部方法 enter - leave
 */
- (void)groupDemo2{
    
    // 问题: 如果 dispatch_group_enter 多 dispatch_group_leave 不会调用通知
    // dispatch_group_enter 少 dispatch_group_leave  奔溃
    // 成对存在
    
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_group_t group = dispatch_group_create();
    
    dispatch_group_enter(group);
    
    // dispatch_group_async -- 下节课的源码分析 --封装意思
    dispatch_async(queue, ^{
        NSLog(@"第一个走完了");
        dispatch_group_leave(group);
    });
    
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        NSLog(@"第二个走完了");
    });
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"所有任务完成,可以更新UI");
    });
}

// 打印
2020-01-27 20:24:49.213355+0800 005---GCD进阶使用(下)[2555:203694] 第一个走完了
2020-01-27 20:24:49.213363+0800 005---GCD进阶使用(下)[2555:203697] 第二个走完了
  • 栅栏函数

在使用栅栏函数时.使用自定义队列才有意义,如果用的是串行队列或者系统提供的全局并发队列,这个栅栏函数的作用等同于一个同步函数的作用

// dispatch_barrier_sync
- (void)demo2{
    
    // 你全部下载完毕之后,我才能处理
    dispatch_queue_t concurrentQueue = dispatch_queue_create("noah", DISPATCH_QUEUE_CONCURRENT);

    // 全局 -- 堵塞
    // 系统GG  -- 设计
    // 这里要注意,如果用的是全局队列,使用栅栏函数是无效的
//    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(0, 0);

    /* 1.异步函数 */
    dispatch_async(concurrentQueue, ^{
        // 请求token -- 线程安全
        for (NSUInteger i = 0; i < 5; i++) {
            NSLog(@"download1-%zd-%@",i,[NSThread currentThread]);
        }
    });
//
    dispatch_async(concurrentQueue, ^{
        for (NSUInteger i = 0; i < 5; i++) {
            NSLog(@"download2-%zd-%@",i,[NSThread currentThread]);
        }
    });
    
    /* 2. 栅栏函数 */
    dispatch_barrier_sync(concurrentQueue, ^{
        NSLog(@"---------------------%@------------------------",[NSThread currentThread]);
    });
    NSLog(@"加载那么多,喘口气!!!");
    /* 3. 异步函数 */
    dispatch_async(concurrentQueue, ^{
        for (NSUInteger i = 0; i < 5; i++) {
            NSLog(@"日常处理3-%zd-%@",i,[NSThread currentThread]);
        }
    });
    NSLog(@"************起来干!!");
    
    dispatch_async(concurrentQueue, ^{
        for (NSUInteger i = 0; i < 5; i++) {
            NSLog(@"日常处理4-%zd-%@",i,[NSThread currentThread]);
        }
    });
    
}

 // 打印
2020-01-27 20:56:33.782415+0800 004--GCD进阶使用[2824:318070] download1-0-<NSThread: 0x60000398a480>{number = 3, name = (null)}
2020-01-27 20:56:33.782420+0800 004--GCD进阶使用[2824:318073] download2-0-<NSThread: 0x600003974240>{number = 4, name = (null)}
2020-01-27 20:56:33.782515+0800 004--GCD进阶使用[2824:318070] download1-1-<NSThread: 0x60000398a480>{number = 3, name = (null)}
2020-01-27 20:56:33.782521+0800 004--GCD进阶使用[2824:318073] download2-1-<NSThread: 0x600003974240>{number = 4, name = (null)}
2020-01-27 20:56:33.782599+0800 004--GCD进阶使用[2824:318070] download1-2-<NSThread: 0x60000398a480>{number = 3, name = (null)}
2020-01-27 20:56:33.782609+0800 004--GCD进阶使用[2824:318073] download2-2-<NSThread: 0x600003974240>{number = 4, name = (null)}
2020-01-27 20:56:33.782659+0800 004--GCD进阶使用[2824:318070] download1-3-<NSThread: 0x60000398a480>{number = 3, name = (null)}
2020-01-27 20:56:33.782694+0800 004--GCD进阶使用[2824:318073] download2-3-<NSThread: 0x600003974240>{number = 4, name = (null)}
2020-01-27 20:56:33.782755+0800 004--GCD进阶使用[2824:318070] download1-4-<NSThread: 0x60000398a480>{number = 3, name = (null)}
2020-01-27 20:56:33.782759+0800 004--GCD进阶使用[2824:318073] download2-4-<NSThread: 0x600003974240>{number = 4, name = (null)}
2020-01-27 20:56:33.782938+0800 004--GCD进阶使用[2824:318033] ---------------------<NSThread: 0x600003902940>{number = 1, name = main}------------------------
2020-01-27 20:56:33.783020+0800 004--GCD进阶使用[2824:318033] 加载那么多,喘口气!!!
2020-01-27 20:56:33.783106+0800 004--GCD进阶使用[2824:318033] ************起来干!!
2020-01-27 20:56:33.783135+0800 004--GCD进阶使用[2824:318070] 日常处理3-0-<NSThread: 0x60000398a480>{number = 3, name = (null)}
2020-01-27 20:56:33.783204+0800 004--GCD进阶使用[2824:318073] 日常处理4-0-<NSThread: 0x600003974240>{number = 4, name = (null)}
2020-01-27 20:56:33.783258+0800 004--GCD进阶使用[2824:318070] 日常处理3-1-<NSThread: 0x60000398a480>{number = 3, name = (null)}
2020-01-27 20:56:33.783343+0800 004--GCD进阶使用[2824:318073] 日常处理4-1-<NSThread: 0x600003974240>{number = 4, name = (null)}
2020-01-27 20:56:33.792221+0800 004--GCD进阶使用[2824:318070] 日常处理3-2-<NSThread: 0x60000398a480>{number = 3, name = (null)}
2020-01-27 20:56:33.792238+0800 004--GCD进阶使用[2824:318073] 日常处理4-2-<NSThread: 0x600003974240>{number = 4, name = (null)}
2020-01-27 20:56:33.792311+0800 004--GCD进阶使用[2824:318070] 日常处理3-3-<NSThread: 0x60000398a480>{number = 3, name = (null)}
2020-01-27 20:56:33.792325+0800 004--GCD进阶使用[2824:318073] 日常处理4-3-<NSThread: 0x600003974240>{number = 4, name = (null)}
2020-01-27 20:56:33.792383+0800 004--GCD进阶使用[2824:318070] 日常处理3-4-<NSThread: 0x60000398a480>{number = 3, name = (null)}
2020-01-27 20:56:33.792399+0800 004--GCD进阶使用[2824:318073] 日常处理4-4-<NSThread: 0x600003974240>{number = 4, name = (null)}
// dispatch_barrier_async函数
/**
 可变数组 线程不安全 解决办法
 */
- (void)demo3{
    
    // 顺序执行
    // 线程安全
    
    dispatch_queue_t concurrentQueue = dispatch_queue_create("cooci", DISPATCH_QUEUE_CONCURRENT);

    // signal -- 线程BUG
    for (int i = 0; i<2000; i++) {
        dispatch_async(concurrentQueue, ^{
            NSString *imageName = [NSString stringWithFormat:@"%d.jpg", (i % 10)];
            NSURL *url = [[NSBundle mainBundle] URLForResource:imageName withExtension:nil];
            NSData *data = [NSData dataWithContentsOfURL:url];
            UIImage *image = [UIImage imageWithData:data];
            // 这代码如果不加处理会导致崩溃,因为多条线程同时操作一块内存会导致崩溃,可以加锁,也可以使用异步栅栏函数去处理 
            //[self.mArray addObject:image];
            dispatch_barrier_async(concurrentQueue, ^{
                [self.mArray addObject:image];
            });
        });
    }
}

其实dispatch_barrier_async与dispatch_barrier_sync两者之间并没有很大的区别,如果用dispatch_barrier_async的话就不会堵塞,用dispatch_barrier_sync就会堵塞,主要看功能代码逻辑去选择用哪个函数,两者的功能是一样的


参考文章

【iOS】玩转 - GCD
GCD的API详解