Bre*_*nan 12 objective-c grand-central-dispatch
我想在循环时让队列等待一小段时间.我正在考虑我的选择,并试图暂停恢复队列,但这似乎需要几个移动部件.所以我正在考虑使用睡眠或睡眠.这更像是一般的线程函数,并且想知道我是否应该避免使用睡眠而是坚持使用GCD选项来使队列暂停.
我发现了一个相关问题,但答案显示他只是错过了一个包含.将GALL队列中的睡眠呼叫混合在一起有什么问题吗?
ipm*_*mcc 10
由于这个问题引起了我多年的悲痛,我想我会分享这种痛苦经历的好处:
每当你sleep在提交给GCD的工作单位中阻止(包括调用)时,你就会创建一个可能导致线程饥饿的情况.更糟糕的是,如果您的工作单元的阻塞是由于使用同步原语(即信号量,锁等),或者如果多个工作单元使用这些原语互锁,则线程饥饿可能导致死锁.更多内容,但这是短版本:
如果您阻止提交给GCD的工作单位:
- 充其量,你使用GCD效率低下.
- 在最坏的情况下,你会让自己暴露于饥饿的可能性,因此(可能)陷入僵局.
原因如下:操作系统具有每进程线程限制.更改每个进程的线程限制并非不可能,但实际上,这样做很少值得.GCD有自己的队列宽度限制(它将用于服务并发队列的线程数).(虽然细节很复杂,但值得注意的是,创建多个并发队列通常不会达到此限制.)根据定义,GCD的限制低于每个进程的线程限制.此外,GCD的队列宽度限制是未记录的实现细节.根据经验,在撰写本文时,在OS X上,我发现限制似乎是64.因为这个限制是一个未记录的实现细节,所以你不能指望知道它是什么.(也不可能使用公共API更改它.)理想情况下,如果GCD将队列宽度限制更改为1,则应编写代码以使其仍然执行完成,尽管速度很慢.(也可能是认为即使一个线程也恰好是主线程也应该如此,但是这会使任务变得更加困难,并且假设总会有至少一个后台线程似乎是安全的,因为它很难值得使用GCD,如果没有.)
你会怎么做?如果您在等待I/O时阻塞,则可能需要考虑转换代码以使用dispatch_io一系列调用.对于准繁忙的等待情况(即原始问题),您可以使用dispatch_after在一段时间后检查某些内容.对于其他情况,调度计时器或调度源可能是适当的.
我将是第一个承认在提交给GCD的工作单位中完全避免阻塞并不总是实用(更不用说权宜之计)了.此外,GCD和Objective-C块语法的结合使得编写富有表现力且易于阅读的代码变得非常简单,以避免通过将阻塞/同步操作移动到后台线程来阻止UI线程的情况.在加快开发方面,这种模式非常有用,我一直都在使用它.也就是说,值得知道的是,使用GCD对工作单元进行排队会占用一定数量的有限资源(即可用的线程数),这些资源的大小,迂腐性地说,无法知道(因为它是一个未记录的实现细节,并且可以实际上,无法控制(因为您无法使用公共API设置/更改GCD的队列宽度.)
关于原始问题:忙碌等待(例如,通过呼叫sleep或usleep)是阻止提交给GCD的工作单位的最可避免和最不可辩护的方法之一.我将进一步做出大胆的声明,即总是有一种更好的,如果不那么快速开发的方式来实现任何可以通过GCD工作单元中的忙等待实现的操作.
*我正在使用"工作单位"来引用提交给GCD执行的Objective-C块或函数指针/参数,以限制与"阻塞"工作的混淆,我的意思是"做一些导致你的线程被暂停的事情"在内核中".
你可以使用sleep,但正如你所提到的,从主线程开始,因为你永远不应该占用主线程.
但是,如果你需要一个小睡眠,时间可能不准确,并且不太可能,但线程将至少在睡眠量之后被唤醒,这取决于其他可能使用cpu的情况.
但是,我发现使用sleep没有任何问题,因为它至少会给其他线程/应用程序提供运行机会.
| 归档时间: |
|
| 查看次数: |
5425 次 |
| 最近记录: |