OC - 19.GCD
简介
- GCD(Grand Center Dispatch)是Apple为多核的并行运算提出的解决方案,纯C语言
- 更加适配多核处理器,且自动管理线程的生命周期,使用起来较为方便
GCD通过任务和队列实现多线程功能
- 任务:描述所要执行的操作
- 队列:用来存放所要执行的任务,队列中的任务遵循FIFO(First In First Out)原则
GCD的任务函数(是否开启新的线程)
同步
- 不具备开启新的线程的能力
同步执行任务的函数
void dispatch_sync(dispatch_queue_t queue, dispatch_block_t block),Block类型
- queue:任务队列
- block(代码块):所执行的任务
void dispatch_sync_f(dispatch_queue_t queue, void *context, dispatch_function_t work),函数类型(每个Block类型都对应一个函数类型)
- queue:任务队列
- context:传递给任务函数的参数
- work(函数):所执行的任务
同步执行任务的其他函数(barrier),在前面的任务执行完毕它才执行,它后边的任务等它执行完毕才执行
void dispatch_barrier_sync(dispatch_queue_t queue, dispatch_block_t block),block类型
- queue:任务队列,仅当该参数为并发队列时,该函数才有意义
dispatch_barrier_sync_f(dispatch_queue_t queue, void *context, dispatch_function_t work),函数类型
异步
- 具备开启新的线程的能力(需要将任务添加到并发队列中)
异步执行任务的函数(参数意义与同步函数相同)
- void dispatch_async(dispatch_queue_t queue, dispatch_block_t block)
- void dispatch_async_f(dispatch_queue_t queue, void *context, dispatch_function_t work)
异步执行任务的其他函数(barrier),在前面的任务执行完毕它才执行,它后边的任务等它执行完毕才执行(参数意义与同步函数相同)
- void dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block)
- void dispatch_barrier_async_f(dispatch_queue_t queue, void *context, dispatch_function_t work)
GCD的队列(任务的执行方式)
并发队列
- 开启多个线程,使队列中的多个任务并发执行(需要异步执行函数的配合)
串行队列
- 队列中的任务一个接一个顺序地执行
队列的种类
串行队列
dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr)
- label:通常为0
- attr:队列类型,DISPATCH_QUEUE_SERIAL
并发队列
dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr)
- label:通常为0
- attr:队列类型 DISPATCH_QUEUE_CONCURRENT
主队列(串行,只能在主线程中运行)
- dispatch_queue_t dispatch_get_main_queue(void),获取主队列
全局队列(并发)
- dispatch_queue_t dispatch_get_global_queue(long identifier, unsigned long flags)
任务与队列的组合
同步函数
同步函数主队列
/**
- 运行在主线程主队列(未开启新的线程),主线程被卡死
- 原因:任务代码等待着当前函数执行完毕才能执行(当前函数正在执行且未执行完毕);
当前函数等待着任务代码 执行完毕才能执行(当前任务正在执行且未执行完毕);
相互等待,出现死锁
*/ //获取主队列
dispatch_queue_t queue = dispatch_get_main_queue();
//添加任务到队列
dispatch_sync(queue, ^{
//任务1代码
});
dispatch_sync(queue, ^{
//任务2代码
});同步函数串行队列
/**
- 运行在主线程串行非主队列(未开启新的线程),任务串行执行
*/ //创建串行队列
dispatch_queue_t queue = dispatch_queue_create("com.23565@qq", DISPATCH_QUEUE_SERIAL);
//添加任务到队列
dispatch_sync(queue, ^{
//任务1代码
});
dispatch_sync(queue, ^{
//任务2代码
});同步函数并发队列
/**
- 运行在非主线程并发队列(未开启新的线程),任务串行执行
*/ //获取全局队列(并发)
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//将任务加至队列
dispatch_sync(queue, ^{
//任务1代码
});
dispatch_sync(queue, ^{
//任务2代码
});
异步函数
异步函数主队列
/**
- 运行在主线程主队列(未开启新的线程),任务串行执行
*/ // 获得主队列
dispatch_queue_t queue = dispatch_get_main_queue();
// 将任务加入队列
dispatch_async(queue, ^{
//任务1代码
});
dispatch_async(queue, ^{
//任务2代码
});异步函数串行队列
/**
- 运行在主函数串行非主队列(未开启新的线程),任务串行执行
*/ //创建串行队列
dispatch_queue_t queue = dispatch_queue_create("com.23565@qq", DISPATCH_QUEUE_SERIAL);
//将任务加至队列
dispatch_async(queue, ^{
//任务1代码
})
dispatch_async(queue, ^{
//任务2代码
})异步函数并发队列
/**
- 运行在非主线程并发队列(开启新的线程),任务并发执行
- 系统根据任务创建线程(无法确定任务执行在哪个线程)
*/ //获得全局并发队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//将任务加入队列
dispatch_async(queue, ^{
//任务1代码
});
dispatch_async(queue, ^{
//任务2代码
});线程之间的通信
从主线程到子线程
注意
- 只有异步函数与并发队列的组合,才会开启新的线程,使任务并发执行
- 通常使用异步函数将任务添加到并发队列中,来实现从主线程到子线程的通信
实现代码
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//需要在子线程中执行的任务代码
})
从子线程到主线程
注意
- 主队列中的任务只能在主线程中执行
- 通常使用异步/同步函数将任务添加到主队列中,来实现从子线程到主线程的通信
实现代码
dispatch_async(dispatch_get_main_queue(), ^{
//需要在主线程中执行的代码
})
GCD的其他任务
单次执行(通常用在单例模式的设计中)
//定义一个标记
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//此处的代码只会被执行一次
});延迟执行
/**
- 方法一(GCD)
*/
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//此处的代码将延迟执行
}); /**
- 方法二(performSelector)
*/
[self performSelector:@selector(run) withObject:self afterDelay:2.0]; /**
- 方法三(NSTimer)
*/
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:NO]
快速迭代
void dispatch_apply(size_t iterations, dispatch_queue_t queue, void (^block)(size_t))
/**
iterations:迭代执行的次数
queue:任务队列
block:迭代执行的代码
size_t:用来定义当前迭代到第几次,需要自己添加,如在size_t后添加index索引,记录当前的迭代次数
*/Barrier
/**
- Barrier中的任务,只能在它前面的任务执行完毕才能执行
Barrier后的任务,只能等到它执行完毕才能执行
- 要将队列添加到自己创建的并发队列中,否其功能等同于函数
void dispatch_async(dispatch_queue_t queue, dispatch_block_t block)
*/
//创建队列(通常是自己创建的并发队列)
dispatch_queue_t queue = dispatch_queue_create("123", DISPATCH_QUEUE_CONCURRENT);
//将任务添加到队列
dispatch_async(queue, ^{
//在Barrier前执行的任务代码
});
dispatch_barrier_async(queue, ^{
//Barrier中的任务代码
});
dispatch_async(queue, ^{
//在Barrier后执行的任务代码
});队列组
//获取全局并发队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//创建队列组
dispatch_group_t group = dispatch_group_create();
//添加任务到队列组
dispatch_group_async(group, queue, ^{
//任务1代码
});
dispatch_group_async(group, queue, ^{
//任务2代码
});
dispatch_group_notify(group, queue, ^{
//任务3代码
/**
group组中的所有任务执行完毕在执行
若group为空,则立即执行
*/
});
GCD定时器
实现原理
- 创建一个DISPATCH_SOURCE_TYPE_TIMER类型的dispatch source,并添加到dispatch queue,通过dispatch source来响应事件
- 通过函数void dispatch_source_set_timer(dispatch_source_t source, dispatch_time_t start, uint64_t interval, uint64_t leeway),来设置dispatch source的执行事件
实现代码
//获得队列
dispatch_queue_t queue = dispatch_get_main_queue();
//创建一个定时器
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); //设置定时器的各种属性(起止时间)
dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(8.0 * NSEC_PER_SEC));
uint64_t interval = (uint64_t)(1.0 * NSEC_PER_SEC);
//设置
dispatch_source_set_timer(self.timer, start, interval, 0); //设置回调
dispatch_source_set_event_handler(self.timer, ^{
//定时器被触发时所要执行的代码
}); //开启定时器
dispatch_resume(self.timer);
//取消定时器
dispatch_cancel(self.timer);
OC - 19.GCD的更多相关文章
- OC - 19.pthread和NSThread
简介 恰当的使用多线程编程可以提供任务的执行效率和系统资源的利用率 多线程是为了提高资源利用率,和应用程序的响应速度,多个线程共享应用资源 每个应用程序都有一个主线程,通常用来做UI界面刷新等 比较耗 ...
- JSPatch学习笔记
本文参考JSPatch wiki :https://github.com/bang590/JSPatch/wiki 1.概念 JSPatch是一个轻量的JS引擎,能够使用JavaScript语言来调用 ...
- IOS 多线程04-GCD详解 底层并发 API
注:本人是翻译过来,并且加上本人的一点见解. 前言 想要揭示出表面之下深层次的一些可利用的方面.这些底层的 API 提供了大量的灵活性,随之而来的是大量的复杂度和更多的责任.在我们的文章常见的后台实践 ...
- IOS线程的一些总结
主线程的作用 (在主线程中才能设置) 显示/刷新UI界面 处理UI事件(比如点击事件.滚动事件.拖拽事件): 主线程的使用注意 别将比较耗时的操作放到主线程中. 耗时操作会卡住主线程.影响体验. [N ...
- 从Objective-C到Swift 单例模式
在Objective-C中经常会用到单例模式.最常见的就是: [UIApplication sharedApplication].delegate 这里的sharedApplication就是一个返回 ...
- ZeroC ICE的远程调用框架 Callback(一)-AMI异步方法调用框架
Ice框架提供了不少回调设施,其中一些是使用Ice远程调用进行ami模式或amd模式的支撑.本篇来看一下用于代理端的回调设施. Ice代码中有好几个Callback相关命名的基类,并且slice还会为 ...
- Hdu1695 GCD 2017-06-27 22:19 30人阅读 评论(0) 收藏
GCD Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submis ...
- 网络与多线程---OC中多线程方法GCD(二)
小编在前一篇中介绍了多线程实现的五种常用方法.在接下来所介绍的这种方法是最具有魅力的,最具有诱惑的实现多线程的方案---GCD 一.什么是GCD GCD是Grand Central Dispatch的 ...
- OC开发_整理笔记——多线程之GCD
一.进程和线程 二.各种队列! 1.GCD:Grand Central Dispatch 2.串行队列(Serial) 你可以创建任意个数的串行队列,每个队列依次执行添加的任务,一个队列 ...
随机推荐
- ifstream文件尾最后一行读两次
看下面一段代码: ifstream m_fileConfig; string str; m_fileConfig.open(FILE_OPERATORS, ios::out ...
- Android 之使用LocalBroadcastManager解决BroadcastReceiver安全问题
在Android系统中,BroadcastReceiver的设计初衷就是从全局考虑的,可以方便应用程序和系统.应用程序之间.应用程序内的通信,所以对单个应用程序而言BroadcastReceiver是 ...
- WindowsPhone 8 开发 之 本地数据库应用
微软提供的有一个本地数据库的例子 http://code.msdn.microsoft.com/wpapps/Local-Database-Sample-57b1614c 可以进行参照. 里边最核心的 ...
- WordPress Shareaholic 插件跨站请求伪造漏洞
漏洞名称: WordPress Shareaholic 插件跨站请求伪造漏洞 CNNVD编号: CNNVD-201308-250 发布时间: 2013-08-19 更新时间: 2013-08-19 危 ...
- extjs几种常用方法
1,提交 这种情况一般用于登录界面,也在表单提交应用比较多,大多是一个Button的提交事件,代码为: var loginForm =........; if (loginForm .form.isV ...
- 【转】VSync Count 垂直同步
原文:http://blog.csdn.net/yesy10/article/details/7794556 Unity3D中新建一个场景空的时候,帧速率(FPS总是很低),大概在60~70之间.一直 ...
- iOS 多线程学习笔记 —— NSThread
本文复制.参考自文章:iOS多线程编程之NSThread的使用 ,主要为了加强个人对知识的理解和记忆,不做他用.原作者声明: 著作权声明:本文由http://blog.csdn.net/totogo ...
- 通过命令名称查询进程id
linux 中如何通过命令名称查询出进程的id呢? 例如,我想查询java的进程id: ps -ef |grep java |grep -v grep|awk '{print $2}' 或者: ps ...
- octopress 如何添加youku视频和本地视频(octopress how to add a youku video or a local video)
用octopress 官方的video tag 可以添加视频,但是由于国内经常使用的是youku,所以下面是如何添加youku视频到octopress的教程. 首先添加youku.rb文件到路径:oc ...
- C++Primer第5版学习笔记(四)
C++Primer第5版学习笔记(四) 第六章的重难点内容 你可以点击这里回顾第四/五章的内容 第六章是和函数有关的知识,函数就是命名了的代码块,可以处理不同的情况,本章内 ...