【发布时间】:2020-08-24 23:20:24
【问题描述】:
我在 GCD 的文档或教程中没有找到一个非常简单的问题:如果我将工作提交到队列的速度快于处理和删除的速度会怎样?我知道 GCD 队列没有大小限制,在程序内存不足之前会一直工作吗?有没有办法妥善处理这种情况?
【问题讨论】:
标签: ios swift grand-central-dispatch
我在 GCD 的文档或教程中没有找到一个非常简单的问题:如果我将工作提交到队列的速度快于处理和删除的速度会怎样?我知道 GCD 队列没有大小限制,在程序内存不足之前会一直工作吗?有没有办法妥善处理这种情况?
【问题讨论】:
标签: ios swift grand-central-dispatch
如果我将工作提交到队列的速度快于处理和删除的速度会怎样?
视情况而定。
如果将任务分派到单个/共享串行队列,它们只会被添加到队列中,并且会以先进先出的方式处理它们。没问题。内存是你唯一的限制。
但是,如果将任务分派到并发队列,最终会导致“线程爆炸”,并且您将很快耗尽可用于该服务质量 (QoS) 的有限数量的工作线程。如果操作系统需要使用相同 QoS 的队列,这可能会导致不可预知的行为。因此,您必须非常小心避免这种线程爆炸。
在 WWDC 2015 Building Responsive and Efficient Apps with GCD 和 WWDC 2016 Concurrent Programming With GCD in Swift 3 中再次查看线程爆炸的讨论。
有没有办法妥善处理这种情况?
很难在摘要中回答这个问题。不同的情况需要不同的解决方案。
在线程爆炸的情况下,解决方案是使用concurrentPerform限制并发程度(将并发限制在设备上的核心数)。或者我们使用操作队列及其maxConcurrentOperationCount 将并发程度限制在合理的范围内。还有其他模式,但想法是将并发限制为适合相关设备的东西。
但是,如果您只是将大量任务分派到串行队列,那么您无能为力(除了寻找并行机会,以有效利用所有 CPU 内核)。但这没关系,因为这是队列的全部目的,让它按照提交的顺序执行任务,即使队列跟不上。如果它不遵循这种先进先出的模式,它就不会是一个“队列”。
现在,如果处理无法足够快地处理的实时数据,您就会遇到不同的问题。在这种情况下,您可能希望将输入的捕获与处理分离,并决定如何处理它。例如。例如,如果您无法跟上视频的实时处理速度,您可以选择。您要么开始丢帧,要么异步/稍后处理数据。您只需要决定什么适合您的用例。我们无法抽象地回答这个问题。
【讨论】:
signal 并且你死锁)。此外,concurrentPerform 针对您的内核数量进行了动态优化,以实现最高效率。但信号量有效。