Ios 如何限制gcd队列缓冲区大小

Ios 如何限制gcd队列缓冲区大小,ios,swift,grand-central-dispatch,metal,core-image,Ios,Swift,Grand Central Dispatch,Metal,Core Image,我正在尝试使用CoreImage&Metal处理一系列UIImages,并显示它们。我的问题是,如果我的gcd块忙,我想删除传入的图像。如何实现此GCD队列,如何定义队列的最大缓冲区大小?GCD队列没有最大队列大小 您可以为此使用信号灯。使用要支持的最大队列长度初始化它。在将任务提交到队列之前,使用dispatch_信号量_wait和dispatch_TIME_NOW作为超时,尝试保留一个位置。如果超时,不要让任务排队放弃它,或者其他什么。任务完成后,让任务向信号量发送信号,释放您为其保留的位置

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

GCD队列没有最大队列大小


您可以为此使用信号灯。使用要支持的最大队列长度初始化它。在将任务提交到队列之前,使用dispatch_信号量_wait和dispatch_TIME_NOW作为超时,尝试保留一个位置。如果超时,不要让任务排队放弃它,或者其他什么。任务完成后,让任务向信号量发送信号,释放您为其保留的位置,以便稍后用于另一个任务。

这没有本机机制,但您可以通过信号量的算法实现所需的功能

在我跳入“过程4一次,但丢弃任何如果我们忙的时候”的情景之前,让我先考虑更简单的“过程所有,但不超过4在任何给定的时间”模式。我将在下面回答你的问题,但以这个更简单的情况为基础

例如,让我们假设您有一些预先存在的对象数组,并且您希望同时处理它们,但在任何给定时间都不超过四个,这可能是为了最大限度地减少峰值内存使用:

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

    for object in objects {
        semaphore.wait()

        processQueue.async {
            self.process(object)
            semaphore.signal()
        }
    }
}
基本上,wait函数将,如前所述,“减少计数信号量。如果结果值小于零,则该函数将等待信号出现,然后返回。”

因此,我们以计数4开始信号量。因此,如果对象中有10个项目,前四个项目将立即启动,但第五个项目将不会启动,直到较早的一个项目完成并发送一个信号,将信号量计数器增加1,依此类推,从而实现“并发运行,但在任何给定时间最多运行4个”行为

那么,让我们回到你的问题上来。假设您希望一次处理不超过四个图像,如果当前正在处理四个图像,则删除任何传入图像。您可以通过告诉wait根本不要真正等待来实现这一点,即,向右检查。现在信号量计数器是否已经达到零,例如:

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那样阻塞主线程,但是因为我使用了超时。现在,它永远不会阻塞,我们只是使用信号量以一种良好的线程安全方式跟踪我们的位置

最后一种方法是考虑操作队列:

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

<> P>行为是稍微不同的,保持最近四个图像排队,准备好,但有点要考虑。< / P>谢谢详细的答案。你能再看看这个问题吗-