如何限制GCD队列缓冲区大小 [英] How to limit gcd queue buffer size

查看:117
本文介绍了如何限制GCD队列缓冲区大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用CoreImage&处理一系列UIImage。金属,并显示它们。我的问题是,如果我的gcd块忙,我想删除传入的图像。如何实现此GCD队列,如何定义队列的最大缓冲区大小?

I am trying to process series of UIImages using CoreImage & Metal and also display them. My problem is I want to drop the incoming image if my gcd block is busy. How do I achieve this GCD queues, how do I define the maximum buffer size of queue?

推荐答案

对此没有本地机制,但是您可以通过信号量实现算法上想要的结果。

There’s no native mechanism for this, but you can achieve what you want algorithmically with semaphores.

在我一次进入过程4之前,但是如果我们很忙则丢弃所有出现的过程在这种情况下,让我首先考虑比较简单的全部处理,但在任何给定时间不超过4个的模式。 (我将在下面回答您的问题,但是基于这种简单情况。)

Before I dive into the "process 4 at a time, but discard any that come if we’re busy" scenario, let me first consider the simpler "process all, but not more than 4 at any given time" pattern. (I’m going to answer your question below, but building on this simpler situation.)

例如,让我们假设您已经存在一些<$ c $的数组c>对象,并且您希望同时处理它们,但在任何给定时间都不能超过四个(也许是为了最大程度地减少峰值内存使用量):

For example, let’s imagine that you had some preexisting array of objects and you want to process them concurrently, but not more than four at any given time (perhaps to minimize peak memory usage):

DispatchQueue.global().async {
    let semaphore = DispatchSemaphore(value: 4)

    for object in objects {
        semaphore.wait()

        processQueue.async {
            self.process(object)
            semaphore.signal()
        }
    }
}

基本上, wait 函数将与< href = https://developer.apple.com/documentation/dispatch/dispatchsemaphore/2016071-wait rel = nofollow noreferrer>文档说,减少计数信号量。如果结果值小于零,则此函数在返回之前等待信号发生。

Basically, the wait function will, as the documentation says, "Decrement the counting semaphore. If the resulting value is less than zero, this function waits for a signal to occur before returning."

因此,我们从4开始计数信号。因此,如果 objects 中包含10个项目,前四个会立即开始,但是第五个要等到其中一个较早的完成并发送 signal (将信号量计数器的值增加1)后才能开始。 ,依此类推,从而实现并发运行,但在任何给定时间最多运行4次的行为。

So, we’re starting our semaphore with a count of 4. So if objects had 10 items in it, the first four would start immediately, but the fifth wouldn’t start until one of the earlier ones finished and sent a signal (which increments the semaphore counter back up by 1), and so on, achieving a "run concurrently, but a max of 4 at any given time" behavior.

,让我们回到您的问题。假设您想一次处理不超过四张图像,并且如果当前已在处理四张图像,则丢弃任何传入图像。您可以通过告诉 wait 根本不真正等待来完成此操作,即,对 .now()进行检查是否正确。信号量计数器已经达到零,例如:

So, let’s return to your question. Let’s say you wanted to process no more than four images at a time and drop any incoming image if there were already four images currently being processed. You can accomplish that by telling wait to not really wait at all, i.e., check right .now() whether the semaphore counter has hit zero already, i.e., something like:

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()
    }
}

注意,我们通常希望避免阻塞主线程(例如 wait 可以),但是因为我使用的是 .now()的超时,所以它永远不会阻塞,我们只是

Note, we generally want to avoid blocking the main thread (like wait can do), but because I’m using a timeout of .now(), it will never block, we’re just use the semaphore to keep track of where we are in a nice, thread-safe manner.

最后一种方法是使用信号量以良好的线程安全方式跟踪我们的位置。考虑操作队列:

One final approach is to consider operation queues:

// 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)
    })
}

此行为略有不同(将最新的四个图像排队,准备就绪),但这是要考虑的事情。

The behavior is slightly different (keeping the most recent four images queued up, ready to go), but is something to consider.

这篇关于如何限制GCD队列缓冲区大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆