本文是来自@FlyOceanFish的投稿

Grand Central Dispatch(GCD)是异步执行任务的技术之一。一般将应用程序中记述的线程管理用的代码在系统级中实现。开发者只需要定义想执行的任务并追加到适当的Dispatch Queue中,GCD就能生成必要的线程并计划执行任务。由于线程管理是作为系统的一部分来实现的,因此可统一管理,也可执行任务,这样就比以前的线程更有效率。

Dispatch Queue将想执行的任务追加到适当的Dispatch QueueDispatch Queue种类说明Serial Dispatch Queue串行队列,任务按照追加顺序处理(FIFO)

Concurrent Dispatch Queue并行队列

串行队列

并行队列

重点

串行队列只有一个线程,并行队列有多个线程。

自建Queuedispatch_queue_t queue = dispatch_queue_create("com.test.queue", DISPATCH_QUEUE_CONCURRENT);//创建了一个并行队列 dispatch_queue_t queue = dispatch_queue_create("com.test.queue", DISPATCH_QUEUE_SERIAL);//创建了一个串行队列

系统QueueMain DispatchQueue 在主线程中执行的Dispatch Queue。因为主线程只有1个,所以Main Dispatch Queue是串行队列。加入到主队列中的任务一定不会生成新的线程,因为主队列必须有且只有一条主线程。

Global Dispatch Queue 一个所有应用程序都能够使用的并发队列。加入到该队列中的任务不一定会生成线程。因为有线程重用的现象

iOS8.0之后的权限名称描述QOS_CLASS_USER_INTERACTIVE与用户交互的任务,这些任务通常跟UI级别的刷新相关,比如动画,这些任务需要在一瞬间完成

QOS_CLASS_USER_INITIATED由用户发起的并且需要立即得到结果的任务,比如滑动scroll view时去加载数据用于后续cell的显示,这些任务通常跟后续的用户交互相关,在几秒或者更短的时间内完成

QOS_CLASS_DEFAULT优先级介于user-initiated 和 utility,当没有 QoS信息时默认使用,开发者不应该使用这个值来设置自己的任务

QOS_CLASS_UTILITY一些可能需要花点时间的任务,这些任务不需要马上返回结果,比如下载的任务,这些任务可能花费几秒或者几分钟的时间

QOS_CLASS_BACKGROUND这些任务对用户不可见,比如后台进行备份的操作,这些任务可能需要较长的时间,几分钟甚至几个小时

QOS_CLASS_UNSPECIFIED未指定

Dispatch Group

dispatch_group是GCD的一项特性,能够把任务分组。调用者可以等待这组任务执行完毕,也可以提供回调函数之后继续往下执行,这组任务完成时,调用者会得到通知。常用场景比如说,下载一个大的文件,分块下载,全部下载完成后再合成一个文件。再比如同时下载多个图片,监听全部下载完后的动作创建groupdispatch_group_t group = dispatch_group_create();添加任务dispatch_group_async(dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block);

将一个任务添加到指定group中

dispatch_group_enter(dispatch_group_t group); dispatch_group_leave(dispatch_group_t group);

这两个函数同上边一样的效果,不过一定要注意这两个函数必须成对出现!否则这一组任务就永远执行不完。

监听任务完成

timeout参数表示函数在等待dispatch group执行完毕后,应该阻塞多久。如果执行dispatch group所需的时间小于timeout,则返回0,否则返回非0值.此参数可以取常量DISPATCH_TIME_FOREVER,这表示函数会一直等着dispatch group 执行完,而不会超时。此方法会阻塞线程。dispatch_group_notify(dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block); 开发者可以传入block,等dispatch group 执行完毕之后,块会在特定的线程上执行,而不阻塞线程。

long dispatch_group_wait(dispatch_group_t group, dispatch_time_t timeout);

*** 使用dispatch_group_notify***

//这个例子演示将将一个很大的字符串删除指定几个字符串。比如“abcdefghicladedgdsfs”删除"ace"三个字符串int const COUNT = 6;@interface ViewController (){    NSMutableArray *values;    dispatch_group_t group;    dispatch_queue_t queue;}@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    values = [NSMutableArray array];    group = dispatch_group_create();    queue = dispatch_queue_create("com.aa.test", DISPATCH_QUEUE_CONCURRENT);    [self removeChars:@"abcdefghicladedgdsfs" target:@"ace"];    dispatch_group_notify(group, queue, ^{        NSString *str = [values componentsJoinedByString:@""];        NSLog(@"%@",str);    });}- (void) removeChars:(NSString *)pBuffer target:(NSString *)target {    for (int i = 0; i

使用dispatch_group_enter和dispatch_group_leavedispatch_group_t group =dispatch_group_create();dispatch_queue_t globalQueue=dispatch_get_global_queue(0, 0);dispatch_group_enter(group);//模拟多线程耗时操作dispatch_group_async(group, globalQueue, ^{    sleep(3);    NSLog(@"%@---block1结束。。。",[NSThread currentThread]);    dispatch_group_leave(group);});NSLog(@"%@---1结束。。。",[NSThread currentThread]);dispatch_group_enter(group);//模拟多线程耗时操作dispatch_group_async(group, globalQueue, ^{    sleep(3);    NSLog(@"%@---block2结束。。。",[NSThread currentThread]);    dispatch_group_leave(group);});NSLog(@"%@---2结束。。。",[NSThread currentThread]);dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{    NSLog(@"%@---全部结束。。。",[NSThread currentThread]);});

dispatch_async和dispatch_syncdispatch_async

dispatch_async将指定的Block异步的追加到指定的Dispatch Queue中。dispatch_async函数不会做任何等待dispatch_sync

dispatch_sync将指定的Block同步的追加到指定的Dispatch Queue。此时dispatch_sync会一直等待Block执行结束之后,才会返回。线程才能接着继续执行其他代码。如dispatch_group_wait函数一样,"等待"意味着当前线程停止。

例:dispatch_sync(dispatch_get_main_queue(), ^{         NSLog(@"测试2");     });

执行以上代码则会直接崩溃。主要是因为dispatch_sync在追加Block的过程中同时在等待,等待意味着当前主线程已经停止,所以主线程无法执行追到到Main Dispatch Queue的Block。Serial Dispatch Queue也会引起同样的问题dispatch_queue_t queue = dispatch_queue_create("com.test.queue", NULL); dispatch_async(queue, ^{         dispatch_sync(queue, ^{             NSLog(@"测试");         });     });

一样的道理,串行队列中只会生成一条线程,而dispatch_sync函数使该线程处于等待状态即停止状态,所以无法将Block追加到com.test.queue这个队列中。

总结:dispatch_sync函数当前queue是串行队列。 当前queue上调用sync函数,并且sync函数中指定的queue也是当前queue。需要执行的block被放到当前queue的队尾等待执行,因为这是一个串行的queue,调用sync函数会阻塞当前队列,等待block执行 这个block永远没有机会执行sync函数不返回,所以当前队列就永远被阻塞了,这就造成了死锁。(这就是问题中在主线程调用sync函数,并且在sync函数中传入main_queue作为queue造成死锁的情况)

当前queue是并行队列。 在并行的queue上面调用sync函数,同时传入当前queue作为参数,并不会造成死锁,因为block会马上被执行,所以sync函数也不会一直等待不返回造成死锁。(并且Block是在当前线程上执行。例如如果是在主线程上调用了dispatch_sync,则Block是在主线程上执行的)

dispatch_async代表异步任务,意思不是一定会生成一条线程。如果在MainQueue中执行,则不会生成线程;如果在Global Queue中有可能会生成。因为线程有一个线程池,会重用已经完成任务了的线程。

栅栏(dispatch_barrier_sync和dispatch_barrier_async)

作用:与并发队列结合,可以高效率的避免数据竞争的问题

相同点:dispatch_barrier_sync和dispatch_barrier_async函数功能一样就是在并发队列中将此代码插入的地方上下隔开,如果栅栏一样,两部分不影响。只有上边的并发队列都执行结束之后,下边的并发队列才能够执行。

不同点:dispatch_barrier_sync代码后边的任务直到dispatch_barrier_sync执行完才能被追加到队列中;dispatch_barrier_async不用代码执行完,后边的任务也会被追加到队列中。代码上的体现就是dispatch_barrier_sync后边的代码不会执行,dispatch_barrier_async后边的代码会执行,但是Block不会被执行。

dispatch_applyThis function submits a block to a dispatch queue for multiple invocations and waits for all iterations of the task block to complete before returning. If the target queue is a concurrent queue returned by dispatch_get_global_queue, the block can be invoked concurrently, and it must therefore be reentrant-safe. Using this function with a concurrent queue can be useful as an efficient parallel for loop.

该函数指定次数将指定的Block追加到指定的Queue中,并等待全部处理执行结束。dispatch_apply(10, dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^(size_t index) {           });

作用:与并发队列结合,可以更有效执行并发任务。

dispatch_suspend/dispatch_resume

挂起指定的Dispatch Queuedispatch_suspend(queue);

恢复指定的Dispatch Queuedispatch_resume(queue);

Dispatch Semaphore

当计数为0时等待,计数为1或大于1时不等待dispatch_semaphore_create(1);//创建1个信号dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);//当计数值大于1时,或者在待机中计数值大于1时,对该计数减1并且返回。dispatch_semaphore_signal(semaphore);//对计数值加1

dispatch_once

单例模式,保证在应用程序中只执行一次指定处理的api。static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{           });

Dispatch I/O

异步串行读取文件NSString *path = [[NSBundle mainBundle] pathForResource:@"iosintroduce" ofType:@"md"]; dispatch_queue_t queue = dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0); dispatch_io_t pipe_chanel = dispatch_io_create_with_path(DISPATCH_IO_STREAM,[path UTF8String], 0, 0,queue , ^(int error) {              }); size_t water = 1024; dispatch_io_set_low_water(pipe_chanel, water); dispatch_io_set_high_water(pipe_chanel, water); NSMutableData *totalData = [[NSMutableData alloc] init];      dispatch_io_read(pipe_chanel, 0, SIZE_MAX, queue, ^(bool done, dispatch_data_t  _Nullable data, int error) {     if (error == 0) {         size_t len = dispatch_data_get_size(data);             if (len > 0) {                 [totalData appendData:(NSData *)data];         }     }     if (done) {         NSString *str = [[NSString alloc] initWithData:totalData encoding:NSUTF8StringEncoding];         NSLog(@"%@", str);     }   });

异步并行读取文件NSString *path = [[NSBundle mainBundle] pathForResource:@"iosintroduce" ofType:@"md"]; dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT); dispatch_fd_t fd = open(path.UTF8String, O_RDONLY); dispatch_io_t io = dispatch_io_create(DISPATCH_IO_RANDOM, fd, queue, ^(int error) {     close(fd); }); off_t currentSize = 0; long long fileSize = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil].fileSize; size_t offset = 1024*1024; dispatch_group_t group = dispatch_group_create(); NSMutableData *totalData = [[NSMutableData alloc] initWithLength:fileSize]; for (; currentSize  0) {                 const void *bytes = NULL;                 (void)dispatch_data_create_map(data, (const void **)&bytes, &len);                 [totalData replaceBytesInRange:NSMakeRange(currentSize, len) withBytes:bytes length:len];             }         }         if (done) {             dispatch_group_leave(group);         }     }); } dispatch_group_notify(group, queue, ^{     NSString *str = [[NSString alloc] initWithData:totalData encoding:NSUTF8StringEncoding];     NSLog(@"%@", str); });dispatch_io_create_with_path通过路径创建一个dispatch_io_t。与之相似的也好几个方法,比如dispatch_io_create_with_io

dispatch_io_set_high_water和dispatch_io_set_low_water 分割文件大小,分别可以设置一次最少读取和一次最多读取多大。

dispatch_io_read读取文件。与之对应的是dispatch_io_write将文件存储到指定路径

如果想提高文件读取速度,可以尝试使用Dispatch I/O。

Dispatch Source

倒计时功能dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());      dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, 15ULL*NSEC_PER_SEC), DISPATCH_TIME_FOREVER, 1ull*NSEC_PER_SEC);      dispatch_source_set_event_handler(timer, ^{         NSLog(@"wake up");         dispatch_source_cancel(timer);   });      dispatch_source_set_cancel_handler(timer, ^{         NSLog(@"canceled");  });      dispatch_resume(timer);

dispatch_after

延迟执行任务dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{              });

最快3秒后执行,最慢3秒+一个runloop循环时间

dispatch_set_target_queue

改变生成的Dispatch Queue的执行优先级//将myQueue优先级设置为与globalQueue相同 dispatch_queue_t myQueue = dispatch_queue_create("com.test.queue", NULL); dispatch_queue_t globalQueue = dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0); dispatch_set_target_queue(myQueue, globalQueue)

第一个参数需要变更优先级的Dispatch Queue,第二个参数指定要使用的执行优先级相同优先级的Queue。

个人博客

ios项目中使用gcd的场景_iOS中超级超级详细介绍GCD相关推荐

  1. 光斑定位技术在空间激光通信中扮演着重要的角色。本文将详细介绍光斑定位的相关知识,并使用Matlab实现一些相关的算法。

    光斑定位技术在空间激光通信中扮演着重要的角色.本文将详细介绍光斑定位的相关知识,并使用Matlab实现一些相关的算法. 一.光斑定位技术 光斑定位技术是一种通过计算像素位置来确定目标物体位置的技术,广 ...

  2. java中char占的二进制,java数据类型与二进制详细介绍

    java数据类型与二进制详细介绍 在java中 Int 类型的变量占 4个字节 Long 类型的变量占8个字节 一个程序就是一个世界,变量是这个程序的基本单位. Java基本数据类型 1. 整数类型 ...

  3. python中uniform(a、b)_关于uniform的详细介绍

    超链接:也叫URL(Uniform Resource Locator),就是统一资源定位器.一般效果是我们点击网页上某个地方,网页会自动跳转到另外一个地方.一般链接遵循以下要求:host.domain ...

  4. html中的content作用,meta name= content=的作用详细介绍

    meta name="" content="的作用详细介绍 发布时间:2013-11-08 16:56:16   作者:佚名   我要评论 meta name=" ...

  5. ios开发读取剪切板的内容_iOS中管理剪切板的UIPasteboard粘贴板类用法详解

    一.自带剪切板操作的原生UI控件在iOS的UI系统中,有3个控件自带剪切板操作,分别是UITextField.UITextView与UIWebView.在这些控件的文字交互处进行长按手势可以在屏幕视图 ...

  6. ios查看ipa是否函数特定字符_iOS 中基础字符判断函数收集(如判断大小写、数字等)...

    函数:isdigit 用法:#include 功能:判断字符c是否为数字 说明:当c为数字0-9时,返回非零值,否则返回零. 函数:islower 用法:#include 功能:判断字符c是否为小写英 ...

  7. ios mysql 创建不同的用户表_iOS中数据库-创建表-增删改查数据-基础语法

    什么是SQL:结构化查询语言.create创建表drop删除表,delete是删除表中的数据 SQL语句不区分大小写,每条语句必须以分号结束,数据库中不可以使用关键字用为表名(sql常用关键字  se ...

  8. linux中的ln属性,linux 常用基础命令 ln 详细介绍

    命令介绍: ln是linux中又一个非常重要命令,ln是为某一个文件在另外一个位置建立一个同步的链接.当我们需要在不同的目录,用到相同的文件时,我们不需要在每一个需要的目录下都放一个必须相同的文件,我 ...

  9. java项目使用过滤器实例_Java web开发--过滤器篇(详细介绍)

    一. web过滤器的介绍 1.过滤器 在生活中,过滤这种我们时常可见:比如水资源的处理,化学药剂的提取等等.所谓过滤,就是指对某事物的处理进行一定的处理获取相应的结果的一个过程.它可以总结为下: 过滤 ...

最新文章

  1. std::map char*做key
  2. 论文笔记之:Instance-aware Semantic Segmentation via Multi-task Network Cascades
  3. 我国手机浏览器用户达2.15亿
  4. function收集
  5. 一个半路出家的前端工程师的2018 | 掘金年度征文
  6. Skywalking 结束孵化,成为 Apache 基金会顶级项目
  7. mysql中decimal与float_MySQL float 与decimal 各中的区别。
  8. [Golang] 第三方包应该如何安装--在线和离线
  9. 解决crontab 定时任务加载失败
  10. 完美:C# Blazor中显示Markdown并添加代码高亮
  11. 2017.12.26
  12. AcWing 896. 最长上升子序列 II(二分优化LIS)
  13. 逆向知识第七讲,三目运算符在汇编中的表现形式,以及编译器优化方式
  14. Unity Transform bug
  15. numpy 矩阵 秩_Python(NumPy):集合只能映射秩1数组
  16. 简述html文档的基本,网页制作简答题答案
  17. 2020字节跳动数据库面试题及答案
  18. C#中使用listview的checkBoxs全选和取消全选
  19. 看看月明光彩照入东 水浒
  20. 【DDNS更新】--公云的DDNS自动更新

热门文章

  1. Hive自定义函数UDF、UDAF、UDTF
  2. 【bzoj 4675】 点对游戏
  3. C# 语言历史版本特性(C# 1.0到C# 8.0汇总)
  4. ubuntu16.04--cuda
  5. 【XSY2718】gift 分数规划 网络流
  6. c#仿照qq登录界面编辑框内容操作
  7. 深刻理解 React (一) ——JSX和虚拟DOM
  8. 动态规划优化_斜率优化
  9. C#使用Monitor类、Lock和Mutex类进行多线程同步
  10. UVA-10817- Headmaster's Headache(状压DP)