GCD(Grand Central Dispatch),主要用于多线程编程。它屏蔽了繁琐的线程实现及管理细节,将其交由系统处理。开发者只需要定义任务block(在底层被封装成dispatch_continuation_t结构体),并提交到正确的dispatch queue中。GCD包含dispatch queue和dispatch source。

一、dispatch queue是FIFO队列,分为两种:

1、serial(串行),队列中的block同一个时刻只会派发给一个线程,所以要等当前block执行完,才会开始执行下一个block。

2、concurrent(并行),队列中的block同一个时刻可能会派发给多个线程,所以多个block可以同时执行。

3、苹果官方说明:

Serial queues (also known as private dispatch queues) execute one task at a time in the order in which they are added to the queue.
The currently executing task runs on a distinct thread (which can vary from task to task) that is managed by the dispatch queue.

注意:串行队列中不同block可能在不同线程执行!

二、使用dispatch queue的方法,也分为两种:

1、dispatch_sync(同步),调用dispatch_sync方法的线程会被阻塞,直到block执行结束。在当前线程调用dispatch_sync方法可能会导致死锁!!!

2、dispatch_async(异步),调用dispatch_async方法的线程不会被阻塞。

NSLog(@"1"); // 死锁,只会输出1
dispatch_sync(currentQueue, ^{
NSlog(@"2"); // block也提交到当前线程对应的队列
});
NSlog(@"3");

死锁的理解:

1、dispatch_sync方法调用和block调用,是当前线程需要处理的两个任务。

2、dispatch_sync方法调用首先提交到队列中。

3、然后block调用提交到队尾,需要等待dispatch_sync方法调用完成。

4、而dispatch_sync方法调用,又需要等到block执行结束才能返回。这就形成了等待环,即死锁。

解决死锁:把block交由另一个线程执行

// 依次输出1、2、3
NSLog(@"1");
dispatch_sync(notCurrentQueue, ^{
NSlog(@"2"); // block提交到另外一个线程对应的队列
});
NSlog(@"3");  

三、创建队列:

dispatch_queue_t dispatch_queue_create(const char *_Nullable label, dispatch_queue_attr_t _Nullable attr);
// label:队列的唯一标识,方便调试
// attr:队列类型,NULL或者DISPATCH_QUEUE_SERIAL表示串行,DISPATCH_QUEUE_CONCURRENT表示并行
dispatch_queue_t serialQueue = dispatch_queue_create("com.tencent.wechat.file", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t concurrentQueue = dispatch_queue_create("com.tencent.wechat.network",DISPATCH_QUEUE_CONCURRENT);  

在MRC下,dispatch_queue_create创建的队列,需要用dispatch_release释放掉。

四、有时候,并不需要开发者创建队列,系统已经提供了两种很好用的队列。

主队列,对应主线程,是个串行队列:

dispatch_queue_t serialMainQueue = dispatch_get_main_queue();

全局队列,是并行队列:

dispatch_queue_t dispatch_get_global_queue(long identifier, unsigned long flags);
// identifier:队列优先级
// flags:通常填0
dispatch_queue_t globalConcurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

  

五、dispatch_after用于延迟执行任务:

void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block);
// 3秒后提交block到主队列,这个时间并不精确,得看当时线程的繁忙程度
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ });

六、dispatch_suspend和dispatch_resume:

1、dispatch_suspend,挂起队列,只会暂停还没执行的任务,已经在执行的任务不会被影响。

2、dispatch_resume,恢复队列,继续调度还没执行的任务。

3、注意,resume一个没有被suspend的队列会导致crash!

七、dispatch_once

详见:https://www.cnblogs.com/yangwenhuan/p/9603472.html

八、dispatch group

在多个并行block都执行完,这就可以用到dispatch group

九、dispatch_set_target_queue

修改优先级

十、dispatch_barrier_async

barrier,顾名思义,添加一个障碍,就是就是个同步点。

dispatch_queue_t globalConcurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// blk1, blk2, blk3并行执行
dispatch_async(globalConcurrentQueue, blk1);
dispatch_async(globalConcurrentQueue, blk2);
dispatch_async(globalConcurrentQueue, blk3);
// blk1, blk2, blk3全部执行完,才开始执行blk4
dispatch_barrier_async(globalConcurrentQueue, blk4);
// blk4执行完,才开始并行执行blk5, blk6
dispatch_async(globalConcurrentQueue, blk5);
dispatch_async(globalConcurrentQueue, blk6);

十一、dispatch_apply

提交特定数量的block到队列中,并等待全部执行结束。dispatch_apply存在与dispatch_sync一样的死锁问题,因此推荐把dispatch_apply放到dispatch_async中执行。

dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(10, q, ^(size_t iter) {
NSLog(@"iteration[%zu]", iter);
});
NSLog(@"done"); 输出:
iteration[3]
iteration[2]
iteration[0]
iteration[4]
iteration[1]
iteration[5]
iteration[9]
iteration[8]
iteration[7]
iteration[6]
done // 最后输出一定是这个 

十二、dispatch semaphore

dispatch semaphore是信号量的封装,可用于实现线程安全,相比串行队列,粒度更小

// 创建信号量,初始值可以不为1
dispatch_semaphore_t s = dispatch_semaphore_create(1);
// 阻塞等待信号量大于等于1
dispatch_semaphore_wait(s, DISPATCH_TIME_FOREVER);
// 信号量减1,开始执行临界区代码 /* 临界区代码 */ // 临界区代码执行结束,信号量+1,最先等待信号量的线程得到执行
dispatch_semaphore_signal(s);

十三、dispatch io

// 获取文件描述符
dispatch_fd_t fd = open(file_path, O_RDWR);
// 创建用于处理dispatch io block的队列
dispatch_queue_t queue = dispatch_queue_create(queue_name, NULL);
// 创建dispatch io,绑定文件描述符
dispatch_io_t io = dispatch_io_create(DISPATCH_IO_STREAM, fd, queue, ^(int error) {
// 异常
close(fd);
});
// 设置一次最多读取的字节数
dispatch_io_set_high_water(io, size);
// 这里书上说会使用global queue来并发读,但是实践没看出来,懂的同学请多多指教
dispatch_io_read(io, 0, max_size, queue, ^(bool done, dispatch_data_t _Nullable data, int error) {
// dispatch_data_t转NSString
dispatch_data_apply(data, ^bool(dispatch_data_t region, size_t offset, const void *buffer, size_t size) {
NSString *sData = [[NSString alloc] initWithBytes:buffer length:size encoding: NSUTF8StringEncoding];
return true;
});
});

十四、dispatch queue VS NSThread, pthread

利用NSThread和pthread也是可以进行多线程编程的,但是

1)需要自己实现线程管理,如分配多少线程、什么时候分配、什么时候销毁等等

2)性能很难比dispatch queue好,因为dispatch queue是基于XNU内核的workqueue实现的(中间还有一层封装是Libc中的pthread_workqueue)

十五、dispatch source

dispatch source是内核kqueue的封装。kqueue是一种多路复用技术,用于监听内核的各种事件通知,并做出相应处理。因为利用回调代替轮询,所以kqueue的CPU占用率很小。

// 创建source
dispatch_source_t dispatch_source_create(dispatch_source_type_t type, uintptr_t handle, unsigned long mask, dispatch_queue_t queue);
// 取消source,已经在执行的handler会继续执行完,还没执行的不再执行
void dispatch_source_cancel(dispatch_source_t source);
// 事件source发生时,执行handler
void dispatch_source_set_event_handler(dispatch_source_t source, dispatch_block_t handler);
// 取消source时,执行handler
void dispatch_source_set_cancel_handler(dispatch_source_t source, dispatch_block_t handler);
// 启动source
void dispatch_resume(dispatch_object_t object);

十六、dispatch queue和block的持有关系

block持有dispatch queue

参考链接:

https://developer.apple.com/library/archive/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html

Objective-C GCD深入理解的更多相关文章

  1. GCD 深入理解

    GCD 深入理解(一) 虽然 GCD 已经出现过一段时间了,但不是每个人都明了其主要内容.这是可以理解的:并发一直很棘手,而 GCD 是基于 C 的 API ,它们就像一组尖锐的棱角戳进 Object ...

  2. GCD API 理解 (一)

    资料先行 GCD 深入理解:第一部分 GCD 深入理解:第二部分 以上两篇文章是关于GCD讲的比较好的文章,翻译自raywenderlich,该网站有很多关于iOS 开发的优秀文章. 引子 iOS 开 ...

  3. GCD 深入理解(二)

    转自@nixzhu的GitHub主页(译者:Riven.@nixzhu),原文<Grand Central Dispatch In-Depth: Part 2/2> 欢迎来到GCD深入理解 ...

  4. GCD深入理解(1)

    写在前面 本文原文为raywenderlich的<grand-central-dispatch-in-depth-part-1>:顺便提及一下,笔者认为,对于iOS初学者而言,raywen ...

  5. GCD 深入理解:第一部分

    虽然 GCD 已经出现过一段时间了,但不是每个人都明了其主要内容.这是可以理解的:并发一直很棘手,而 GCD 是基于 C 的 API ,它们就像一组尖锐的棱角戳进 Objective-C 的平滑世界. ...

  6. GCD 深入理解(一)

    http://www.cocoachina.com/industry/20140428/8248.html 本文由@nixzhu翻译至raywenderlich的<grand-central-d ...

  7. IOS GCD 的理解

    GCD (Grand Central Dispatch) 是Apple公司开发的一种技术,它旨在优化多核环境中的并发操作并取代传统多线程的编程模式. 在Mac OS X 10.6和IOS 4.0之后开 ...

  8. GCD 深入理解:第二部分

    在本系列的第一部分中,你已经学到超过你想像的关于并发.线程以及GCD 如何工作的知识.通过在初始化时利用 dispatch_once,你创建了一个线程安全的 PhotoManager 单例,而且你通过 ...

  9. GCD的深入理解

    GCD 深入理解(一) 本文由@nixzhu翻译至raywenderlich的<grand-central-dispatch-in-depth-part-1> 虽然 GCD 已经出现过一段 ...

随机推荐

  1. 【IDEA&&Eclipse】4、IntelliJ IDEA上操作GitHub

    IntelliJ IDEA集成了对GitHub的支持,使上传代码到GitHub和从GitHub下载代码更加方便快捷. 1. 分享代码到GitHub 首先需要在IntelliJ配置Git,如果没有正确配 ...

  2. C#设计模式--迭代器模式(学习Learning hard设计模式笔记)

    /// <summary> /// 抽象聚合接口 /// </summary> public interface IListCollection { Iterator GetI ...

  3. JavaScript中的递归

    译者按: 程序员应该知道递归,但是你真的知道是怎么回事么? 原文: All About Recursion, PTC, TCO and STC in JavaScript 译者: Fundebug 为 ...

  4. 复盘价值1000万的腾讯云硬盘固件"BUG"

    摘要: 除了吃瓜,还是得吸取教训啊同学们! 这次,我从纯技术角度分析腾讯云与前沿数控的磁盘数据丢失事件,不站队. 硬盘门 这里说的硬盘门不是10年前陈老师的那一次,而聊的是最近"腾讯云&qu ...

  5. Django Rest framework 之 版本

    RESTful 规范 django rest framework 之 认证(一) django rest framework 之 权限(二) django rest framework 之 节流(三) ...

  6. Python 简单的远程执行命令

    client端执行命令,server端返回命令结果 # server 端 import socket, subprocess sk = socket.socket() address=('127.0. ...

  7. 【读书笔记】iOS-应用内购买

    Store Kit框架是一个应用内支付引擎.通过这个框架,付费应用可以实现用户付费购买内容的功能(比如为了获取额外的内容) 如果你发现Store Kit框架很难用,而且应用内付款不需要服务器端的支持, ...

  8. html学习笔记——ife task0001

    花了两三天大概看完html和css基本用法,但到自己布局的时候还是很懵不知道从哪里入手啊,就找了个简单的任务(ife2015 spring)试一下. 之前不涉及到布局的跳过,从涉及到position和 ...

  9. express koa koa2 优缺点分析

    发布日期 2009年6月26日,TJ 提交 Express 第一次 commit.目前拥有 5000 多次 commit. 2013年8月17日, TJ 只身一人提交 Koa 第一次 commit.目 ...

  10. 我的Java之旅 第八课 Servlet 进阶API、过滤器与监听器

    1.Servlet.ServletConfig与GenericServlet     首次请求的顺序      => 生成HttpServletRequest与HttpServletRespon ...