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

时间:2017-10-14 17:59:29

标签: swift macos memory parallel-processing grand-central-dispatch

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

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

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

所以我想找到一种方法“以最大化并行化的速率”为“并行任务处理器”提供服务,同时将工作量保持在RAM中(因此没有任何触发器进行分页和交换:我想避免磁盘IO)。

关于如何做到这一点的任何想法?

2 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:0)

我最终实现了一个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()
    }
}