- 浏览: 1316849 次
- 性别:
- 来自: 成都
文章分类
- 全部博客 (471)
- 原创文章 (4)
- Database (84)
- J2SE (63)
- Web (26)
- Javascript (30)
- Lucene (11)
- os (13)
- 算法 (8)
- Webservice (1)
- Open projects (18)
- Hibernate (18)
- Spring (15)
- Css (2)
- J2ee (2)
- 综合技术 (18)
- 安全管理 (13)
- PatternsInJava (27)
- NIO (5)
- Ibatis (2)
- 书籍收藏 (1)
- quartz (7)
- 并发编程 (15)
- oracle问题 (2)
- ios (60)
- coco2d-iphone (3)
- C++ (6)
- Zookeeper (2)
- golang (4)
- animation (2)
- android (1)
最新评论
-
dandingge123:
【引用】限制UITextField输入长度的方法 -
qja:
...
对List顺序,逆序,随机排列实例代码 -
安静听歌:
现在在搞这个,,,,,哎~头都大了,,,又freemarker ...
通用大型网站页面静态化解决方案(一) -
springdata-jpa:
java quartz定时任务demo教程源代码下载,地址:h ...
Quartz 配置参考 -
马清天:
[b][/b][list][*]引用[u][/u][/list ...
通用大型网站页面静态化解决方案(一)
GCD介绍(三): Dispatch Sources
- 博客分类:
- ios
转自 http://www.dreamingwish.com/dream-2012/gcd%E4%BB%8B%E7%BB%8D%EF%BC%88%E4%B8%89%EF%BC%89-dispatch-sources.html
何为Dispatch Sources
简单来说,dispatch source是一个监视某些类型事件的对象。当这些事件发生时,它自动将一个block放入一个dispatch queue的执行例程中。
说的貌似有点不清不楚。我们到底讨论哪些事件类型?
下面是GCD 10.6.0版本支持的事件:
- Mach port send right state changes.
- Mach port receive right state changes.
- External process state change.
- File descriptor ready for read.
- File descriptor ready for write.
- Filesystem node event.
- POSIX signal.
- Custom timer.
- Custom event.
这是一堆很有用的东西,它支持所有kqueue所支持的事件(kqueue是什么?见http://en.wikipedia.org/wiki/Kqueue)以及mach(mach是什么?见http://en.wikipedia.org/wiki/Mach_(kernel))端口、内建计时器支持(这样我们就不用使用超时参数来创建自己的计时器)和用户事件。
用户事件
这些事件里面多数都可以从名字中看出含义,但是你可能想知道啥叫用户事件。简单地说,这种事件是由你调用dispatch_source_merge_data函数来向自己发出的信号。
这个名字对于一个发出事件信号的函数来说,太怪异了。这个名字的来由是GCD会在事件句柄被执行之前自动将多个事件进行联结。你可以将数据“拼接”至dispatch source中任意次,并且如果dispatch queue在这期间繁忙的话,GCD只会调用该句柄一次(不要觉得这样会有问题,看完下面的内容你就明白了)。
用户事件有两种: DISPATCH_SOURCE_TYPE_DATA_ADD
和 DISPATCH_SOURCE_TYPE_DATA_OR
.用户事件源有个 unsigned long data
属性,我们将一个 unsigned long
传入 dispatch_source_merge_data
。当使用 _ADD
版本时,事件在联结时会把这些数字相加。当使用 _OR
版本时,事件在联结时会把这些数字逻辑与运算。当事件句柄执行时,我们可以使用dispatch_source_get_data函数访问当前值,然后这个值会被重置为0。
让我假设一种情况。假设一些异步执行的代码会更新一个进度条。因为主线程只不过是GCD的另一个dispatch queue而已,所以我们可以将GUI更新工作push到主线程中。然而,这些事件可能会有一大堆,我们不想对GUI进行频繁而累赘的更新,理想的情况是当主线程繁忙时将所有的改变联结起来。
用dispatch source就完美了,使用DISPATCH_SOURCE_TYPE_DATA_ADD,我们可以将工作拼接起来,然后主线程可以知道从上一次处理完事件到现在一共发生了多少改变,然后将这一整段改变一次更新至进度条。
啥也不说了,上代码:
dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, dispatch_get_main_queue()); dispatch_source_set_event_handler(source, ^{ [progressIndicator incrementBy:dispatch_source_get_data(source)]; }); dispatch_resume(source); dispatch_apply([array count], globalQueue, ^(size_t index) { // do some work on data at index dispatch_source_merge_data(source, 1); });
(对于这段代码,我很想说点什么,我第一次用dispatch source时,我纠结了很久很久,真让人崩溃:Dispatch source启动时默认状态是挂起的,我们创建完毕之后得主动恢复,否则事件不会被传递,也不会被执行)
假设你已经将进度条的min/max值设置好了,那么这段代码就完美了。数据会被并发处理。当每一段数据完成后,会通知dispatch source并将dispatch source data加1,这样我们就认为一个单元的工作完成了。事件句柄根据已完成的工作单元来更新进度条。若主线程比较空闲并且这些工作单元进行的比较慢,那么事件句柄会在每个工作单元完成的时候被调用,实时更新。如果主线程忙于其他工作,或者工作单元完成速度很快,那么完成事件会被联结起来,导致进度条只在主线程变得可用时才被更新,并且一次将积累的改变更新至GUI。
现在你可能会想,听起来倒是不错,但是要是我不想让事件被联结呢?有时候你可能想让每一次信号都会引起响应,什么后台的智能玩意儿统统不要。啊。。其实很简单的,把你的思想放到禁锢的框子之外就行了。如果你想让每一个信号都得到响应,那使用dispatch_async函数不就行了。实际上,使用的dispatch source而不使用dispatch_async的唯一原因就是利用联结的优势。
内建事件
上面就是怎样使用用户事件,那么内建事件呢?看看下面这个例子,用GCD读取标准输入:
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_source_t stdinSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, STDIN_FILENO, 0, globalQueue); dispatch_source_set_event_handler(stdinSource, ^{ char buf[1024]; int len = read(STDIN_FILENO, buf, sizeof(buf)); if(len > 0) NSLog(@"Got data from stdin: %.*s", len, buf); }); dispatch_resume(stdinSource);
简单的要死!因为我们使用的是全局队列,句柄自动在后台执行,与程序的其他部分并行,这意味着对这种情况的提速:事件进入程序时,程序正在处理其他事务。
这是标准的UNIX方式来处理事务的好处,不用去写loop。如果使用经典的 read
调用,我们还得万分留神,因为返回的数据可能比请求的少,还得忍受无厘头的“errors”,比如 EINTR
(终端系统调用)。使用GCD,我们啥都不用管,就从这些蛋疼的情况里解脱了。如果我们在文件描述符中留下了未读取的数据,GCD会再次调用我们的句柄。
对于标准输入,这没什么问题,但是对于其他文件描述符,我们必须考虑在完成读写之后怎样清除描述符。对于dispatch source还处于活跃状态时,我们决不能关闭描述符。如果另一个文件描述符被创建了(可能是另一个线程创建的)并且新的描述符刚好被分配了相同的数字,那么你的dispatch source可能会在不应该的时候突然进入读写状态。de这个bug可不是什么好玩的事儿。
适当的清除方式是使用 dispatch_source_set_cancel_handler
,并传入一个block来关闭文件描述符。然后我们使用 dispatch_source_cancel
来取消dispatch source,使得句柄被调用,然后文件描述符被关闭。
使用其他dispatch source类型也差不多。总的来说,你提供一个source(mach port、文件描述符、进程ID等等)的区分符来作为diapatch source的句柄。mask参数通常不会被使用,但是对于 DISPATCH_SOURCE_TYPE_PROC
来说mask指的是我们想要接受哪一种进程事件。然后我们提供一个句柄,然后恢复这个source(前面我加粗字体所说的,得先恢复),搞定。dispatch source也提供一个特定于source的data,我们使用 dispatch_source_get_data
函数来访问它。例如,文件描述符会给出大致可用的字节数。进程source会给出上次调用之后发生的事件的mask。具体每种source给出的data的含义,看man page吧。
计时器
计时器事件稍有不同。它们不使用handle/mask参数,计时器事件使用另外一个函数 dispatch_source_set_timer
来配置计时器。这个函数使用三个参数来控制计时器触发:
start
参数控制计时器第一次触发的时刻。参数类型是 dispatch_time_t
,这是一个opaque类型,我们不能直接操作它。我们得需要dispatch_time
和 dispatch_walltime
函数来创建它们。另外,常量 DISPATCH_TIME_NOW
和 DISPATCH_TIME_FOREVER
通常很有用。
interval
参数没什么好解释的。
leeway
参数比较有意思。这个参数告诉系统我们需要计时器触发的精准程度。所有的计时器都不会保证100%精准,这个参数用来告诉系统你希望系统保证精准的努力程度。如果你希望一个计时器没五秒触发一次,并且越准越好,那么你传递0为参数。另外,如果是一个周期性任务,比如检查email,那么你会希望每十分钟检查一次,但是不用那么精准。所以你可以传入60,告诉系统60秒的误差是可接受的。
这样有什么意义呢?简单来说,就是降低资源消耗。如果系统可以让cpu休息足够长的时间,并在每次醒来的时候执行一个任务集合,而不是不断的醒来睡去以执行任务,那么系统会更高效。如果传入一个比较大的leeway给你的计时器,意味着你允许系统拖延你的计时器来将计时器任务与其他任务联合起来一起执行。
总结
现在你知道怎样使用GCD的dispatch source功能来监视文件描述符、计时器、联结的用户事件以及其他类似的行为。由于dispatch source完全与dispatch queue相集成,所以你可以使用任意的dispatch queue。你可以将一个dispatch source的句柄在主线程中执行、在全局队列中并发执行、或者在用户队列中串行执行(执行时会将程序的其他模块的运算考虑在内)。
下一篇我会讨论如何对dispatch queue进行挂起、恢复、重定目标操作;如何使用dispatch semaphore;如何使用GCD的一次性初始化功能。
发表评论
-
ios 声音合成
2013-08-18 13:20 1242http://stackoverflow.com/ques ... -
__bridge,__bridge_retained和__bridge_transfer的意思,区别与使用 20 三
2012-12-24 01:41 1651使用ARC能帮我们减轻不少内存管理方面的负担,尤其是对用 ... -
CAAnimation
2012-12-23 01:09 2308CAAnimation采用了CAMediaTi ... -
UIViewAnimation动画与Core Animation的CATransition类动画
2012-12-23 01:06 2703使用UIView类函数实现://U ... -
GCD实战2:资源竞争
2012-12-23 01:04 1558转自http://www.dreamingwish.co ... -
GCD实战一:使用串行队列实现简单的预加载
2012-12-22 17:10 2830转自 http://www.dreamingwish.c ... -
GCD介绍(四): 完结
2012-12-22 17:08 1337转自 http://www.dreamingwish.c ... -
GCD介绍(二): 多核心的性能
2012-12-22 17:05 1156转自http://www.dreamingwish.co ... -
基本概念和Dispatch Queue
2012-12-22 17:03 1324转自 http://www.dreamingwish.c ... -
Best Audio Format for iPhone Audio Programming
2012-12-19 16:26 2512I had never done audio p ... -
LAME 是一个开源的MP3解码编码工具
2012-12-19 13:09 8507MP3 Encoding * 编码MP3文件必须按如下 ... -
sqlite3中的数据类型
2012-12-10 21:37 1274(转)http://www.cnblogs.com/kfqco ... -
ios随机数,and()、random()、arc4random()
2012-11-15 11:06 4696原文:http://bj007.blog.51cto.c ... -
IPHONE GIF 播放的方式
2012-10-11 18:30 1418转 http://blog.csdn.net/zltia ... -
在新线程中使用NSTimer
2012-10-11 18:21 1557转自 http://blog.csdn.net/sjzs ... -
Creating an iPhone Daemon – Part 5
2012-09-02 15:29 1509Creating an iPhone Daemon – ... -
Creating an iPhone Daemon – Part 4
2012-09-02 15:28 1384Creating an iPhone Daemon – ... -
Creating an iPhone Daemon – Part 3
2012-09-02 15:25 1480This is part three of the bl ... -
Creating an iPhone Daemon – Part 2
2012-09-02 15:24 1226Here is part two of the blog ... -
Creating an iPhone Daemon – Part 1
2012-09-02 15:23 1137So I thought I would start t ...
相关推荐
定义:GCD是苹果公司开发的一套多线程编程的API,用于简化多线程编程的复杂性。 功能:GCD提供了一个易于使用的、基于任务的并发模型,可以将任务提交给系统,系统会自动管理线程的创建、销毁和调度,以实现最佳的...
MHA安装依赖包
dispatch_queue_t queue = dispatch_queue_create("com.gcd-dispatch_group_async(gro
http://blog.csdn.net/totogo2010/article/details/8016129 例子代码
vim-dispatch:dispatch.vim:异步构建和测试调度程序
Log-Dispatch-2.69.tar.gz,Log-Dispatch-2.69.tar.gz,Log-Dispatch-2.69.tar.gz,MHA安装的依赖包
Macaw::dispatch(); 支持Lambda URL: Macaw::get('/(:any)', function($slug) { echo 'The slug is: ' . $slug; }); Macaw::dispatch(); 也可以发起 HTTP 请求: Macaw::get('/', function() { ...
1、信号量:就是一种可用来控制访问资源的数量的标识,设定了一个信 2、信号量主要有3个函数,分别是: 3、那么就开头提的问题,我们用代码来解决
有关Dispatch Solo(作为OVA分发的Dispatch版本)的信息,请参阅或。 Dispatch是用于部署和管理无服务器样式的应用程序的框架。 目的是使开发人员能够构建由处理业务逻辑的功能定义的应用程序和提供所有其他功能的...
dispatch-vimshell.vim 策略可实现惊人的。 安装 使用您首选的插件安装方法并安装: (vimshell要求) (早于 ) 用法 以与通常使用vim-dispatch相同的方式使用它。 现在,Vimshell是首选策略。 现在支持除后台...
KillerRabbit 是 THGDispatch 模块,包括 GCD bits:Queues, Groups, Timer, Semaphore 等等。使用:执行异步闭包:Dispatch().async(.Background) { doSomething() }在后台队列执行异步闭包:Dispatch().async(....
1、通过dispatch_barrier_(a)sync添加的block会等待前边所有的block执行完(不包括回调)才执行。 2、在其后添加的block会在dispatch_barrier_(a)sync添加的block执行完之后(不包括回调)再执行; 不同点: 1、...
var dispatch = d3 . dispatch ( "start" , "end" ) ; 然后,您可以使用为这些事件注册回调: dispatch . on ( "start" , callback1 ) ; dispatch . on ( "start.foo" , callback2 ) ; dispatch . on ( "end" , ...
异步OC 用Objective-C重写... 代替熟悉的GCD语法: dispatch_async (dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0 ), ^{ NSLog ( @" A: This is run on the background " ); dispatch_async ( dis
以上两种方式都是模拟任务block内为异步操作的情况,方式一先执行的dispatch_group_notify里的代码,后执行的dispatch_group_async里的任务代码,这与我们的初衷相违背。如果任务block内为同步操作时,则无论哪种...
DISPATCH
MHA-manager、MHA-agent,支持Redhet6、7,MySQL高可用MHA安装包。
Dispatch IDS for IExplorer Dispatch Events
软件介绍: 注:本软件需要.net 3.5的支持,请先安装.net 3.5Connectify Dispatch Hotspot Pro 4是一款网络带宽叠加软件,它可以让你三网合一,把不同的网络叠加到一起给你带来更快的网线速度。通过它你可以...
异步的Objective-C中的语法糖,用于Grand Central Dispatch... 代替熟悉的GCD语法: dispatch_async (dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0 ), { NSLog ( @" ===>>> This is run on the b