Dee*_*rma 0 core-image grand-central-dispatch ios swift metal
我正在尝试使用 CoreImage & Metal 处理一系列 UIImages 并显示它们。我的问题是如果我的 gcd 块很忙,我想删除传入的图像。我如何实现这个 GCD 队列,我如何定义队列的最大缓冲区大小?
没有针对此的本地机制,但是您可以使用信号量在算法上实现您想要的。
在我深入研究“一次处理 4 个,但如果我们很忙时丢弃任何出现的”场景,让我首先考虑更简单的“处理所有,但在任何给定时间不超过 4 个”模式。(我将在下面回答您的问题,但以这种更简单的情况为基础。)
例如,假设您有一些预先存在的数组,objects并且您想同时处理它们,但在任何给定时间不超过四个(可能是为了最大限度地减少峰值内存使用量):
DispatchQueue.global().async {
let semaphore = DispatchSemaphore(value: 4)
for object in objects {
semaphore.wait()
processQueue.async {
self.process(object)
semaphore.signal()
}
}
}
Run Code Online (Sandbox Code Playgroud)
基本上,wait正如文档所说,该函数将“减少计数信号量。如果结果值小于零,则此函数在返回之前等待信号发生。”
所以,我们以 4 的计数开始我们的信号量。所以如果其中objects有 10 个项目,前四个将立即开始,但第五个不会开始,直到较早的一个完成并发送一个signal(这会增加信号量计数器备份 1),依此类推,实现“并发运行,但在任何给定时间最多为 4”行为。
那么,让我们回到你的问题。假设您希望一次处理不超过四张图像,如果当前已经处理了四张图像,则删除任何传入的图像。您可以通过告诉wait根本不要真正等待来实现这一点,即,检查.now()信号量计数器是否已经达到零,即,类似于:
let semaphore = DispatchSemaphore(value: 4)
let processQueue = DispatchQueue(label: "com.domain.app.process", attributes: .concurrent)
func submit(_ image: UIImage) {
if semaphore.wait(timeout: .now()) == .timedOut { return }
processQueue.async {
self.process(image)
self.semaphore.signal()
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,我们通常希望避免阻塞主线程(就像wait可以做的那样),但是因为我使用的是 超时.now(),它永远不会阻塞,我们只是使用信号量来跟踪我们在一个好的位置,线程安全的方式。
最后一种方法是考虑操作队列:
// create queue that will run no more than four at a time (no semaphores needed; lol)
let processQueue: OperationQueue = {
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 4
return queue
}()
func submit(_ image: UIImage) {
// cancel all but the last three unstarted operations
processQueue.operations
.filter { $0.isReady && !$0.isFinished && !$0.isExecuting && !$0.isCancelled }
.dropLast(3)
.forEach { $0.cancel() }
// now add new operation to the queue
processQueue.addOperation(BlockOperation {
self.process(image)
})
}
Run Code Online (Sandbox Code Playgroud)
行为略有不同(保持最近的四个图像排队,准备就绪),但需要考虑。
| 归档时间: |
|
| 查看次数: |
1390 次 |
| 最近记录: |