iOS GCD使用
Grand Central Dispatch(GCD)是异步运行任务的技术之中的一个。
一般将应用程序中记述的线程管理用的代码在系统级中实现。开发人员仅仅须要定义想运行的任务并追加到适当的Dispatch Queue中,GCD就能生成必要的线程并计划运行任务。因为线程管理是作为系统的一部分来实现的。因此可统一管理。也可运行任务,这样就比曾经的线程更有效率。
Dispatch Queue
Dispatch Queue是用来运行任务的队列,是GCD中最主要的元素之中的一个。
Dispatch Queue分为两种:
- Serial Dispatch Queue,按加入进队列的顺序(先进先出)一个接一个的运行
- Concurrent Dispatch Queue。并发运行队列里的任务
let myQueue: dispatch_queue_t = dispatch_queue_create("com.xxx", nil)
第一个參数是队列的名称,通常是使用倒序的全域名。
尽管能够不给队列指定一个名称,可是有名称的队列能够让我们在遇到问题时更好调试;当第二个參数为nil时返回Serial Dispatch Queue,如上面那个样例。当指定为DISPATCH_QUEUE_CONCURRENT时返回Concurrent Dispatch Queue。
须要注意一点,假设是在OS X 10.8或iOS 6以及之后版本号中使用,Dispatch Queue将会由ARC自己主动管理,假设是在此之前的版本号。须要自己手动释放,例如以下:
let myQueue: dispatch_queue_t = dispatch_queue_create("com.xxx", nil)
dispatch_async(myQueue, { () -> Void in
println("in Block")
})
dispatch_release(myQueue)
以上是通过手动创建的方式来获取Dispatch Queue,另外一种方式是直接获取系统提供的Dispatch Queue。
要获取的Dispatch Queue无非就是两种类型:
- Main Dispatch Queue
- Global Dispatch Queue / Concurrent Dispatch Queue
//获取Main Dispatch Queue
let mainQueue = dispatch_get_main_queue()
//获取Global Dispatch Queue
)
得到的Global Dispatch Queue实际上是一个Concurrent Dispatch Queue。Main Dispatch Queue实际上就是Serial Dispatch Queue(而且仅仅有一个)。
dispatch_after
dispatch_after能让我们加入进队列的任务延时运行,比方想让一个Block在10秒后运行:
* NSEC_PER_SEC))
dispatch_after(time, globalQueue) { () -> Void in
println("在10秒后运行")
}
NSEC_PER_SEC表示的是秒数,它还提供了NSEC_PER_MSEC表示毫秒。
上面这句dispatch_after的真正含义是在10秒后把任务加入进队列中,并非表示在10秒后运行,大部分情况该函数能达到我们的预期,仅仅有在对时间要求很精准的情况下才可能会出现故障。
获取一个dispatch_time_t类型的值能够通过两种方式来获取,以上是第一种方式。即通过dispatch_time函数。还有一种是通过dispatch_walltime函数来获取,dispatch_walltime须要使用一个timespec的结构体来得到dispatch_time_t。通常dispatch_time用于计算相对时间。dispatch_walltime用于计算绝对时间。我写了一个把NSDate转成dispatch_time_t的Swift方法:
func getDispatchTimeByDate(date: NSDate) -> dispatch_time_t {
let interval = date.timeIntervalSince1970
var second = 0.0
let subsecond = modf(interval, &second)
var time = timespec(tv_sec: __darwin_time_t(second), tv_nsec: (Int)(subsecond
* (Double)(NSEC_PER_SEC)))
)
}
这种方法接收一个NSDate对象,然后把NSDate转成dispatch_walltime须要的timespec结构体,最后再把dispatch_time_t返回,相同是在10秒后运行,之前的代码在调用部分须要改动成:
))
dispatch_after(time, globalQueue) { () -> Void in
println("在10秒后运行")
}
这就是通过绝对时间来使用dispatch_after的样例。
dispatch_group
这个时候就须要使用dispatch_group了:
)
let group = dispatch_group_create()
dispatch_group_async(group, globalQueue) { () -> Void in
println("1")
}
dispatch_group_async(group, globalQueue) { () -> Void in
println("2")
}
dispatch_group_async(group, globalQueue) { () -> Void in
println("3")
}
dispatch_group_notify(group, globalQueue) { () -> Void in
println("completed")
}
- 312
- completed
除了使用dispatch_group_notify函数能够得到最后运行完的通知外。还能够使用
)
let group = dispatch_group_create()
dispatch_group_async(group, globalQueue) { () -> Void in
println("1")
}
dispatch_group_async(group, globalQueue) { () -> Void in
println("2")
}
dispatch_group_async(group, globalQueue) { () -> Void in
println("3")
}
//使用dispatch_group_wait函数
dispatch_group_wait(group, DISPATCH_TIME_FOREVER)
println("completed")
须要注意的是。dispatch_group_wait实际上会使当前的线程处于等待的状态。也就是说假设是在主线程运行dispatch_group_wait。在上面的Block运行完之前,主线程会处于卡死的状态。
能够注意到dispatch_group_wait的第二个參数是指定超时的时间,假设指定为DISPATCH_TIME_FOREVER(如上面这个样例)则表示会永久等待,直到上面的Block所有运行完。除此之外。还能够指定为详细的等待时间。依据dispatch_group_wait的返回值来推断是上面block运行完了还是等待超时了。
dispatch_barrier_async
dispatch_barrier_async就如同它的名字一样,在队列运行的任务中添加“栅栏”,在添加“栅栏”之前已经開始运行的block将会继续运行,当dispatch_barrier_async開始运行的时候其它的block处于等待状态,dispatch_barrier_async的任务运行完后,其后的block才会运行。我们简单的写个样例。如果这个样例有读文件和写文件的部分:
func writeFile() {
,
forKey: "Integer_Key")
}
func readFile(){
print(NSUserDefaults.standardUserDefaults().integerForKey("Integer_Key"))
}
写文件仅仅是在NSUserDefaults写入一个数字7,读仅仅是将这个数字打印出来而已。我们要避免在写文件时候正好有线程来读取,就使用dispatch_barrier_async函数:
, forKey: "Integer_Key")
)
dispatch_async(globalQueue) {self.readFile()}
dispatch_async(globalQueue) {self.readFile()}
dispatch_async(globalQueue) {self.readFile()}
dispatch_async(globalQueue) {self.readFile()}
dispatch_barrier_async(globalQueue) {self.writeFile() ; self.readFile()}
dispatch_async(globalQueue) {self.readFile()}
dispatch_async(globalQueue) {self.readFile()}
dispatch_async(globalQueue) {self.readFile()}
我们先将一个9初始化到NSUserDefaults的Integer_Key中,然后在中间运行dispatch_barrier_async函数。因为这个队列是一个Concurrent Dispatch Queue。能同一时候并发多少线程是由系统决定的。假设加入dispatch_barrier_async的时候,其它的block(包含上面4个block)还没有開始运行,那么会先运行dispatch_barrier_async里的任务。其它block所有处于等待状态。
假设加入dispatch_barrier_async的时候,已经有block在运行了,那么dispatch_barrier_async会等这些block运行完后再运行。
dispatch_apply
)
, globalQueue) { (index) -> Void in
print(index)
}
print("completed")
由于是Concurrent Dispatch Queue,不能保证哪个索引的元素是先运行的,可是“completed”一定是在最后打印,由于dispatch_apply函数是同步的,运行过程中会使线程在此处等待,所以一般的,我们应该在一个异步线程里使用dispatch_apply函数:
)
dispatch_async(globalQueue, { () -> Void in
, globalQueue) { (index) -> Void in
print(index)
}
print("completed")
})
print("在dispatch_apply之前")
dispatch_suspend / dispatch_resume
//暂停
dispatch_suspend(globalQueue)
//恢复
dispatch_resume(globalQueue)
暂停时。假设已经有block正在运行,那么不会对该block的运行产生影响。dispatch_suspend仅仅会对还未開始运行的block产生影响。
Dispatch Semaphore
其他想进入该关键代码段的线程必须等待前面的线程释放信号量。
)
)
... {
dispatch_async(globalQueue, { () -> Void in
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
let time = dispatch_time(DISPATCH_TIME_NOW,
(Int64 * NSEC_PER_SEC))
dispatch_after(time, globalQueue) { () -> Void in
print("2秒后运行")
dispatch_semaphore_signal(semaphore)
}
})
}
取得信号量的线程在2秒后释放了信息量。相当于是每2秒运行一次。
dispatch_once
class SingletonObject {
class var sharedInstance : SingletonObject {
struct Static {
static var instance : SingletonObject? = nil
}
dispatch_once(&Static.onceToken) {
Static.instance = SingletonObject()
}
return Static.instance!
}
}
这样就能通过GCD的安全机制保证这段代码仅仅运行一次。
iOS GCD使用的更多相关文章
- iOS GCD基础篇 - 同步、异步,并发、并行的理解
1.关于GCD - GCD全称是Grand Central Dispatch - GCD是苹果公司为多核的并行运算提出的解决方案 - GCD会自动利用更多的CPU内核(比如双核.四核) - GC ...
- iOS GCD之dispatch_semaphore(信号量)
前言 最近在看AFNetworking3.0源码时,注意到在 AFURLSessionManager.m 里面的 tasksForKeyPath: 方法 (L681),dispatch_semapho ...
- iOS GCD 编程小结
一.简单介绍 1.GCD简介? 全称是Grand Central Dispatch,可译为“牛逼的中枢调度器” 纯C语言,提供了非常多强大的函数 2.GCD优势 GCD是苹果公司为多核的并行运算提出的 ...
- iOS GCD NSOperation NSThread等多线程各种举例详解(拷贝)
2年多的iOS之路匆匆而过,期间也拜读来不少大神的博客,近来突然为自己一直做伸手党感到羞耻,是时候回馈社会.回想当年自己还是小白的时候,照着一些iOS多线程教程学,也只是照抄,只知其然.不知其所以然. ...
- ios - GCD简单小结
首先GCD两个名词: 队列 同步异步. 队列: 任务放到队列,队列中的任务执行方式取决于执行队列中任务的方式---同步异步. 串行队列: 任务顺序执行,可以叫阻塞队列.只有前面任务完成才执行后面的. ...
- iOS GCD 与 NSOperationQueue
NSOperationQueue ios NSOperation vs. GCD StackOverflow: NSOperation vs. Grand Central Dispatch Blog: ...
- IOS GCD 使用 (二)
上一节,主要介绍了GCD的基本的概念,这节将用代码深入详细介绍GCD的使用. 一 使用介绍 GCD的使用主要分为三步:创建代码块;选择或创建合适的分发队列;(同步.异步方式)向分发队列提交任 ...
- iOS——GCD多线程
1> 概述 Grand Central Dispatch (GCD)是Apple开发的一种多核编程技术.主要用于优化应用程序以支持多核处理器以及其他对称多处理系统. GCD提供函数实现多线程开发 ...
- IOS GCD 的理解
GCD (Grand Central Dispatch) 是Apple公司开发的一种技术,它旨在优化多核环境中的并发操作并取代传统多线程的编程模式. 在Mac OS X 10.6和IOS 4.0之后开 ...
- IOS GCD使用实例大全
GCD是大家在IOS开发过程中经常使用的一种多线程管理机制.原理这里就不多说了,大家关心的大部分都是它的使用,下面主要介绍GCD的主要方法及其实例. 1.认识主队列,感受串行队列的运行,运行结果打印的 ...
随机推荐
- web结对项目
一.Coding.Net项目地址: https://git.coding.net/verde/Pair_Work.git 二.对接口进行的设计 看教科书和其它资料中关于Informati ...
- webpack的像素转vw单位的loader插件
安装: npm i px2vw-view-loader 配置: 按以下loader格式,添加进入webpack配置文件,实现从px转换成vw,适用于移动端项目 module: { rules: [{ ...
- iOS学习笔记48-Swift(八)反射
一.Swift反射 所谓反射就是可以动态获取类型.成员信息,在运行时可以调用方法.属性等行为的特性. 在使用OC开发时很少强调其反射概念,因为OC的Runtime要比其他语言中的反射强大的多.不过在S ...
- [luoguP1110] [ZJOI2007]报表统计(set暴力)
传送门 两个multiset 一个记录相邻元素的差,一个放所有的元素 2个数组 val[i]记录第i个的值,last[i]记录第i个最后插入的数的值 然后乱搞 #include <set> ...
- 开源 project
移动:http://www.csdn.net/article/2014-04-22/2819435-facebook-mobile-open-source-projects/1
- 【BZOJ2286】消耗战(虚树,DFS序,树形DP)
题意:一棵N个点的树上有若干个关键点,每条边有一个边权,现在要将这些关键点到1的路径全部切断,切断一条边的代价就是边权. 共有M组询问,每组询问有k[i]个关键点,对于每组询问求出完成任务的最小代价. ...
- linux 时间模块 三
LINUX的时钟中断中涉及至二个全局变量一个是xtime,另一个则是jiffies.有一个与时间有关的时钟:实时时钟(RTC),这是一个硬件时钟,用来持久存放系统时间,系统关闭后靠主板上的微型电池保持 ...
- MYSQL无法连接,提示10055错误尝试解决
解决方法:(以下内容为本人亲自实践原创)总结一下,应该是连接数的问题,那么服务器上有些什么连接数:1.IIS网站服务器中各个网站中有“连接超时时间”,“会话超时时间”:2.其它程序占用的服务器连接数( ...
- invoke反射
mark一下使用用法,原理以后在搞: 无参数: import java.text.SimpleDateFormat; import java.util.Date; import java.lang.r ...
- spring boot--日志、开发和生产环境切换、自定义配置(环境变量)
Spring Boot日志常用配置: # 日志输出的地址:Spring Boot默认并没有进行文件输出,只在控制台中进行了打印 logging.file=/home/zhou # 日志级别 debug ...