我想在队列循环时等待一段时间。我正在考虑我的选择,并试图暂停恢复队列,但这似乎需要几个移动部件。所以我正在考虑使用睡眠或睡眠。这更像是一般的线程函数,并想知道我是否应该避免使用睡眠而是坚持使用GCD选项来暂停队列。
我发现了一个相关的问题,但答案显示他只是错过了一个包含。将睡眠呼叫与GCD队列混合是否有任何问题?
iphone - is it ok to use usleep on a secondary thread on Grand Central Dispatch?
答案 0 :(得分:10)
由于这个问题引起了我多年的悲痛,我想我会分享痛苦经历的好处:
如果您在提交给GCD的工作单位*中阻止(包括调用sleep
),您将创建一个可能导致线程饥饿的情况。更糟糕的是,如果您的工作单元的阻塞是由于使用同步原语(即信号量,锁等),或者如果多个工作单元使用这些原语互锁,则线程饥饿可能导致死锁。更多内容,但这是短版本:
如果您阻止提交给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块或函数指针/参数,以限制与“阻塞”工作的混淆,我的意思是“做一些事情”导致您的线程在内核中挂起“。
答案 1 :(得分:7)
你可以使用sleep,但正如你所提到的,从主线程开始,因为你永远不应该占用主线程。
但是,如果你需要一个小睡眠,时间可能不准确,并且不太可能,但线程将至少在睡眠量之后被唤醒,这取决于其他可能使用的CPU。
但是,我发现使用sleep没有任何问题,因为它至少会给其他线程/应用程序一个机会来运行。
答案 2 :(得分:1)
在Grand Central Dispatch中使用sleep可能有点问题,因为GCD会对线程进行池化,因此您可以阻止其他作业使用该线程。 GCD可以创造更多的线程,但是在这种情况下我会避免睡觉的人员,这取决于具体情况。