文档章节

iOS多线程的初步研究(八)-- dispatch队列

小春0618
 小春0618
发布于 2015/06/21 16:44
字数 1300
阅读 303
收藏 9

3 月,跳不动了?>>>

GCD编程的核心就是dispatch队列,dispatch block的执行最终都会放进某个队列中去进行,它类似NSOperationQueue但更复杂也更强大,并且可以嵌套使用。所以说,结合block实现的GCD,把函数闭包(Closure)的特性发挥得淋漓尽致。 dispatch队列的生成可以有这几种方式:

 1. dispatch_queue_t queue = dispatch_queue_create("com.dispatch.serial", DISPATCH_QUEUE_SERIAL); //生成一个串行队列,队列中的block按照先进先出(FIFO)的顺序去执行,实际上为单线程执行。第一个参数是队列的名称,在调试程序时会非常有用,所有尽量不要重名了。

 2. dispatch_queue_t queue = dispatch_queue_create("com.dispatch.concurrent", DISPATCH_QUEUE_CONCURRENT); //生成一个并发执行队列,block被分发到多个线程去执行

 3. dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //获得程序进程缺省产生的并发队列,可设定优先级来选择高、中、低三个优先级队列。由于是系统默认生成的,所以无法调用dispatch_resume()和dispatch_suspend()来控制执行继续或中断。

需要注意的是,三个队列不代表三个线程,可能会有更多的线程。并发队列可以根据实际情况来自动产生合理的线程数,也可理解为dispatch队列实现了一个线程池的管理,对于程序逻辑是透明的。 

官网文档解释说共有三个并发队列,但实际还有一个更低优先级的队列,设置优先级为DISPATCH_QUEUE_PRIORITY_BACKGROUND。Xcode调试时可以观察到正在使用的各个dispatch队列。 

 4. dispatch_queue_t queue = dispatch_get_main_queue(); //获得主线程的dispatch队列,实际是一个串行队列。同样无法控制主线程dispatch队列的执行继续或中断。 接下来我们可以使用dispatch_async或dispatch_sync函数来加载需要运行的block。 

 dispatch_async(queue, ^{   //block具体代码 }); //异步执行block,函数立即返回 

 dispatch_sync(queue, ^{   //block具体代码 }); //同步执行block,函数不返回,一直等到block执行完毕。编译器会根据实际情况优化代码,所以有时候你会发现block其实还在当前线程上执行,并没用产生新线程。 实际编程经验告诉我们,尽可能避免使用dispatch_sync,嵌套使用时还容易引起程序死锁。 如果queue1是一个串行队列的话,这段代码立即产生死锁:  

 dispatch_sync(queue1, ^{      

dispatch_sync(queue1, ^{     ......   });   

......  

}); 

 不妨思考下,为什么下面代码在主线程中执行会死锁: 

 dispatch_sync(dispatch_get_main_queue(), ^{   ...... }); 

 那实际运用中,一般可以用dispatch这样来写,常见的网络请求数据多线程执行模型: dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{   

//子线程中开始网络请求数据   

//更新数据模型   

dispatch_sync(dispatch_get_main_queue(), ^{     

//在主线程中更新UI代码   

}); 

 }); 程序的后台运行和UI更新代码紧凑,代码逻辑一目了然。 

 dispatch队列是线程安全的,可以利用串行队列实现锁的功能。比如多线程写同一数据库,需要保持写入的顺序和每次写入的完整性,简单地利用串行队列即可实现: 

 dispatch_queue_t queue1 = dispatch_queue_create("com.dispatch.writedb", DISPATCH_QUEUE_SERIAL); 

 - (void)writeDB:(NSData *)data {   

dispatch_async(queue1, ^{     

//write database   

}); 

 } 

 下一次调用writeDB:必须等到上次调用完成后才能进行,保证writeDB:方法是线程安全的。 

 dispatch队列还实现其它一些常用函数,包括: 

 void dispatch_apply(size_t iterations, dispatch_queue_t queue, void (^block)(size_t)); //重复执行block,需要注意的是这个方法是同步返回,也就是说等到所有block执行完毕才返回,如需异步返回则嵌套在dispatch_async中来使用。多个block的运行是否并发或串行执行也依赖queue的是否并发或串行。 

 void dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block); //这个函数可以设置同步执行的block,它会等到在它加入队列之前的block执行完毕后,才开始执行。在它之后加入队列的block,则等到这个block执行完毕后才开始执行。 

 void dispatch_barrier_sync(dispatch_queue_t queue, dispatch_block_t block); //同上,除了它是同步返回函数 

void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block); //延迟执行block 最后再来看看dispatch队列的一个很有特色的函数: 

void dispatch_set_target_queue(dispatch_object_t object, dispatch_queue_t queue); 它会把需要执行的任务对象指定到不同的队列中去处理,这个任务对象可以是dispatch队列,也可以是dispatch源(以后博文会介绍)。而且这个过程可以是动态的,可以实现队列的动态调度管理等等。比如说有两个队列dispatchA和dispatchB,这时把dispatchA指派到dispatchB:

 dispatch_set_target_queue(dispatchA, dispatchB); 

那么dispatchA上还未运行的block会在dispatchB上运行。

这时如果暂停dispatchA运行: 

 dispatch_suspend(dispatchA); 

则只会暂停dispatchA上原来的block的执行,dispatchB的block则不受影响。而如果暂停dispatchB的运行,则会暂停dispatchA的运行。 这里只简单举个例子,说明dispatch队列运行的灵活性,在实际应用中你会逐步发掘出它的潜力。 dispatch队列不支持cancel(取消),没有实现dispatch_cancel()函数,不像NSOperationQueue,不得不说这是个小小的缺憾。

本文转载自:http://www.cnblogs.com/sunfrog/p/3305614.html?utm_source=tuicool

上一篇: 关键帧动画
下一篇: SDWebImage源码解析
小春0618
粉丝 8
博文 40
码字总数 10552
作品 0
海淀
程序员
私信 提问
加载中

评论(0)

关于iOS多线程,这边勉强可以看看(OC&Swift)

iOS开发多线程总是绕不过的坎,看了很多前辈们优秀的文章,如:关于iOS多线程,我说,你听,没准你就懂了!、谈iOS多线程(NSThread、NSOperation、GCD)编程、iOS多线程:『GCD』详尽总结、i...

Andy_Ron
2018/08/26
0
0
iOS multiple threads(2)------GCD

前面一二也说过,iOS中多线程编程工具主要有: NSThread NSOperation GCD 这三种方法都简单易用,各有千秋.同NSThread相比,GCD的运行效率更高,开发更简单。 但GCD确是诱惑力的,因为其本身是...

辉兔狼
2013/03/24
581
0
iOS中GCD的魔力

GCD(Grand Central Dispatch)是一个大的主题。它可以提高代码的执行效率与多核的利用率。是苹果的开源项目,如果你是一个追求软件效率的开发人员,这门技术你一定要有所研究。 今天要介绍的是...

长平狐
2012/08/13
367
0
dispatch_sync和dispatch_async的区别

dispatchsync 线程同步、dispatchasync线程异步 //同步 这些代码输出的结果是 1 2 3 4 依次输出、无论你运行多少次都会是这一种结果 但是来看下面的异步呢? //并行队列、同步 输出的结果是 ...

久依
2019/01/10
0
0
Flutter 与 iOS 混合项目初探

背景 大厂小厂都在搞Flutter,就问你慌不慌! 国内一些混合集成方案的文章大部分都太老了,参考价值不高,并且很容易让初学者头大。 前言 本文非阐述Flutter相关的原理,优势,发展现状等问题...

Inlight先森
2019/12/19
0
0

没有更多内容

加载失败,请刷新页面

加载更多

mysql默认事务隔离级别

引言 开始我们的内容,相信大家一定遇到过下面的一个面试场景 面试官:“讲讲mysql有几个事务隔离级别?” 你:“读未提交,读已提交,可重复读,串行化四个!默认是可重复读” 面试官:“为...

HJCui
44分钟前
19
0
并发编程概念篇-02并行与并发

并行与并发区别举个例子,如果有一条高速公路上面有4条车道,那么最大的并行车辆就是4辆,此条高速公路同时并排行驶的车辆小于等于4辆的时候,车辆就可以并行行驶,CPU也是这个原理,一个CPU...

wangmob
48分钟前
31
0
如何删除所有已合并的Git分支? - How can I delete all Git branches which have been merged?

问题: I have many Git branches. 我有很多Git分支。 How do I delete branches which have already been merged? 如何删除已经合并的分支? Is there an easy way to delete them all inst......

技术盛宴
58分钟前
34
0
【Maven】maven 插件开发实战

<a name="lkFfi"></a> 前言 <br />众所周知,maven 实质上是一个插件执行框架,所有的工作都是通过插件完成的。包括我们日常使用到的类似 install、clean、deploy、compiler。。。这些命令,...

K1W1
今天
16
0
本科操作系统课练习3(和尚取水问题C++ Windows代码-多线程信号量)

某寺庙,有小和尚、老和尚若干。有一水缸,由小和尚提水入缸,老和尚从缸中取水饮用。水缸可容纳10桶水,水取自同一水井中,水井径窄,每次只能容一个水桶取水。水桶总数为3个,每次入、取缸...

whywhywhywhywhy
昨天
22
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部