如何在swift中实现并行映射

Aru*_*yal 3 parallel-processing concurrency ios swift

我有以下代码:-

extension Collection {

    // EZSE : A parralelized map for collections, operation is non blocking
    public func pmap<R>(_ each: (Self.Iterator.Element) -> R) -> [R?] {
        let indices = indicesArray()
        var res = [R?](repeating: nil, count: indices.count)

        DispatchQueue.concurrentPerform(iterations: indices.count) { (index) in
            let elementIndex = indices[index]
            res[index] = each(self[elementIndex])
        }

        // Above code is non blocking so partial exec on most runs
        return res
    }

    /// EZSE : Helper method to get an array of collection indices
    private func indicesArray() -> [Self.Index] {
        var indicesArray: [Self.Index] = []
        var nextIndex = startIndex
        while nextIndex != endIndex {
            indicesArray.append(nextIndex)
            nextIndex = index(after: nextIndex)
        }
        return indicesArray
    }
}
Run Code Online (Sandbox Code Playgroud)

在return语句res处,通常会返回部分执行完成的结果。有道理,并发执行是非阻塞的。我不确定如何继续等待。我应该使用调度组/期望之类的东西还是有一些更简单更优雅的方法?本质上,我正在快速寻找一个简单的等待通知抽象。

Had*_*dus 6

@user28434 的答案很好,可以通过使用使其更快concurrentPerform

extension Collection {
    func parallelMap<R>(_ transform: @escaping (Element) -> R) -> [R] {
        var res: [R?] = .init(repeating: nil, count: count)

        let lock = NSRecursiveLock()
        DispatchQueue.concurrentPerform(iterations: count) { i in
            let result = transform(self[index(startIndex, offsetBy: i)])
            lock.lock()
            res[i] = result
            lock.unlock()
        }

        return res.map({ $0! })
    }
}
Run Code Online (Sandbox Code Playgroud)

OperationQueue()它与在我正在运行的任务上使用(在 10,000 个项目上并行运行我的某些函数)进行比较,使用 100 次运行来平均:

  • concurrentPerform平均需要 0.060 秒。
  • OperationQueue()平均需要 0.087 秒。