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这样来写,常见的网络请求数据多线程执行模型:

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_sync(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_tqueue, dispatch_block_t block); //延迟执行block

最后再来看看dispatch队列的一个很有特色的函数:

void dispatch_set_target_queue(dispatch_object_t object, dispatch_queue_tqueue);

它会把需要执行的任务对象指定到不同的队列中去处理,这个任务对象可以是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队列运行的灵活性,在实际应用中你会逐步发掘出它的潜力。

iOS多线程的初步研究(八)-- dispatch队列的更多相关文章

  1. iOS多线程的初步研究(六)

    iOS多线程的初步研究(六) iOS平台提供更高级的并发(异步)调用接口,让你可以集中精力去设计需完成的任务代码,避免去写与程序逻辑无关的线程生成.运行等管理代码.当然实质上是这些接口隐含生成线程和管 ...

  2. iOS多线程的初步研究3

    iOS多线程的初步研究(三) 弄清楚NSRunLoop确实需要花时间,这个类的概念和模式似乎是Apple的平台独有(iOS+MacOSX),很难彻底搞懂(iOS没开源,呜呜). 官网的解释是说run ...

  3. iOS多线程的初步研究1

    iOS多线程的初步研究(一) 对于多线程的开发,iOS系统提供了多种不同的接口,先谈谈iOS多线程最基础方面的使用.产生线程的方式姑且分两类,一类是显式调用,另一类是隐式调用. 一.显示调用的类为NS ...

  4. iOS多线程的初步研究

    iOS多线程的初步研究(四) 理解run loop后,才能彻底理解NSTimer的实现原理,也就是说NSTimer实际上依赖run loop实现的. 先看看NSTimer的两个常用方法: + (NST ...

  5. iOS多线程的初步研究(九)-- dispatch源

    dispatch源(dispatch source)和RunLoop源概念上有些类似的地方,而且使用起来更简单.要很好地理解dispatch源,其实把它看成一种特别的生产消费模式.dispatch源好 ...

  6. iOS多线程的初步研究(七)-- dispatch对象

    谈起iOS的dispatch(正式称谓是Grand Central Dispatch或GCD),不得不说这又是iOS(包括MacOSX)平台的创新,优缺点这里不讨论,只有当你使用时才能真正体会到.我们 ...

  7. iOS多线程的初步研究(十)-- dispatch同步

    GCD提供两种方式支持dispatch队列同步,即dispatch组和信号量. 一.dispatch组(dispatch group) 1. 创建dispatch组 dispatch_group_t ...

  8. iOS多线程的初步研究(一)-- NSThread

    对于多线程的开发,iOS系统提供了多种不同的接口,先谈谈iOS多线程最基础方面的使用.产生线程的方式姑且分两类,一类是显式调用,另一类是隐式调用. 一.显示调用的类为NSThread.一般构造NSTh ...

  9. iOS多线程的初步研究(六)-- NSOperation

    iOS平台提供更高级的并发(异步)调用接口,让你可以集中精力去设计需完成的任务代码,避免去写与程序逻辑无关的线程生成.运行等管理代码.当然实质上是这些接口隐含生成线程和管理线程的运行,从而更加简洁地实 ...

随机推荐

  1. Java开发手册

    <Java开发手册> 基本信息 作者: 桂颖    谷涛    出版社:电子工业出版社 ISBN:9787121209161 上架时间:2013-8-12 出版日期:2013 年7月 开本 ...

  2. Selenium 脚本稳定性问题

    运行一个星期前升至更久前的脚本,,,出现如下错误提示 elementNotVisibleException was unhandled by user code. 经过询问大侠,说我的脚本不够健全,也 ...

  3. 自动化运维工具Ansible详细部署 - 人生理想在于坚持不懈 - 51CTO技术博客

    自动化运维工具Ansible详细部署 - 人生理想在于坚持不懈 - 51CTO技术博客 自动化运维工具Ansible详细部署

  4. 与IO相关的等待事件troubleshooting-系列5

    'db file scattered read'         这是另一种常见的等待事件.他产生于Oracle从磁盘读取多个块到Buffer Cache中非连续(" scattered&q ...

  5. 402. Remove K Digits

    (English version is after the code part) 这个题做起来比看起来容易,然后我也没仔细想,先速度刷完,以后再看有没有改进. 用这个来说: 1 2 4 3 2 2 1 ...

  6. Bash简单介绍

    Bash不不过一个命令解析程序. 它本身拥有一种程序设计语言,使用这样的语言,能够编写shell脚本来完毕各种各样的工作.而这些工作是使用现成的命令所无法完毕的.Bash脚本能够使用if-then-e ...

  7. ICOPclient版本号,异步connect

    之前在网上看到一个服务端的ICOP模块,比較小巧,感觉还不错,后来在工作中,需要开发一个挂号的程序,监视大量server执行情况,初期连接数大概六七百,我就把这个ICOP模块改造成了一个client版 ...

  8. Boost.Asio c++ 网络编程翻译(20)

    异步服务端 这个图表是相当复杂的:从Boost.Asio出来你能够看到4个箭头指向on_accept.on_read,on_write和on_check_ping. 着也就意味着你永远不知道哪个异步调 ...

  9. JAVA基于AE调用GP实现泰森多边形

    调用GP实现数据处理是较快捷.较易入手的方法. 使用JAVA语言基于AE调用GP实现泰森多边形的代码例如以下: public void CreatVoronoi(){ try { GeoProcess ...

  10. sqlserver 数据行统计,秒查语句

    1.传统统计方式                                                                                             ...