如何在不 运行 内存不足的情况下尽可能并行化我的 macOS 应用程序任务?

How can I parallelize my macOS app tasks as much as possible without running out of memory?

我在 macOS 上有一个 Swift 应用 运行ning。它批处理图像。我事先不知道这些图像有多大,以及我的应用程序将 运行 使用什么硬件 - 这些都取决于用户。

我使用 GCD 来并行处理图像,因为它确实可以加快吞吐量。

然而,在某些情况下,过多的并行化会带来伤害:如果用户处理高分辨率图像,并行化会造成过多的内存压力,系统的性能会变得很差。

所以我想找到一种方法 "feed my parallel task processor" 以最大化并行化的速率同时将工作负载保持在 RAM 中(因此没有任何触发分页和交换:我想避免磁盘IO).

关于如何做到这一点有什么想法吗?

有一个 GCD dispatch source 内存压力事件。不确定您的代码是如何构建的,但是是否可以创建并行任务直到您收到 DISPATCH_MEMORYPRESSURE_WARN 事件,然后停止创建任务甚至杀死一些任务?

我最终实现了一个 TokenBucket 类型的单例,它根据内存需求处理准入控制。它被初始化,以便我的应用程序可以使用 80% 的 RAM。

let memoryGate = MemoryGate(maxBytes: ProcessInfo.processInfo.physicalMemory*8/10)

当有人想要执行内存密集型操作时,它必须从中请求()内存。如果没有足够的内存,调用将阻塞直到有足够的内存。完成后,线程必须释放()内存。

代码:

class MemoryGate {

    private let maxBytes : UInt64
    private var availableBytes : Int64

    private let cv = NSCondition()

    init(maxBytes: UInt64) {
        self.maxBytes = maxBytes
        self.availableBytes = Int64(maxBytes)
        Log.debug?.message("maxBytes=\(maxBytes)")
    }

    public func request(amount: UInt64) {
        Log.debug?.message("Resquesting \(amount) bytes")
        cv.lock()

        // If the amount is bigger than the max allowed, no amount of waiting is going
        // to help, so we go through and let the other smaller jobs be held back until
        // memory is freed
        if (amount <= maxBytes) {
            while (availableBytes < Int64(amount)) {
                cv.wait()
            }
        }

        availableBytes -= Int64(amount)

        Log.debug?.message("Got \(amount) bytes. availableBytes=\(availableBytes)")
        cv.unlock()
    }

    public func release(amount: UInt64) {
        cv.lock()
        availableBytes += Int64(amount)
        Log.debug?.message("Released \(amount) bytes. availableBytes=\(availableBytes)")
        cv.broadcast()
        cv.unlock()
    }
}