Swift 3 Parallel for/map Loop

Ric*_*ett 4 parallel-processing grand-central-dispatch swift

这里有相当多的线程然而在Swift中使用Grand Central Dispatch来并行化并加速"for"循环?使用Swift <3.0代码而我无法在3中工作(参见代码).并行处理数组使用GCD使用指针并且它有点难看所以我要在这里断言我正在寻找好的Swift 3方法(当然尽可能高效).我也听说组很慢(?也许有人可以证实这一点.我也无法让小组工作.

这是我对跨步并行映射函数的实现(在Array的扩展中).它希望在全局队列上执行,以便不阻止UI.可能是并发位不需要在范围内,只需要余数循环.

extension Array {

    func parallelMap<R>(striding n: Int, f: @escaping (Element) -> R, completion: @escaping ([R]) -> ()) {
        let N = self.count
        var res = [R?](repeating: nil, count: self.count)
        DispatchQueue.global(qos: .userInitiated).async {
            DispatchQueue.concurrentPerform(iterations: N/n) {k in
                for i in (k * n)..<((k + 1) * n) {
                    res[i] = f(self[i]) //Error 1 here
                }
            }
            //remainder loop
            for i in (N - (N % n))..<N {
                res[i] = f(self[i])
            }
            DispatchQueue.main.sync { //But it will pause on this line.
                print("\nPlease work!\n") //This doesn't execute either.
                completion(unwrap(res)!) //Error 2 here, or rather "not here"
            }
        }
    }

}   

public func unwrap<T>(_ arr: Array<T?>) -> Array<T>? {
    if (arr.contains{$0 == nil}) {
        return nil
    } else {
        return arr.map{(x: T?) -> T in x!}
    }
}
Run Code Online (Sandbox Code Playgroud)

错误1:我们EXC_BAD_ACCESS在内部数组分配线上的老朋友大约一半我测试它.我猜这是一个同时访问问题.

错误2:completion永远不会执行!

错误3:错误继续存在,我确信一旦修复上述错误就会发生.

最后:代码为最快的并行(确保它尽可能并行,我不喜欢我的代码中的'并发')map/for function possible.这是修复我的代码的补充.

Rob*_*ier 7

马丁最初的方法仍然是正确的方法.将你的方法与他的方法合并并转换为Swift 3是相当简单的(虽然我摆脱了你的选项并且只是手工处理了内存).

extension Array {
    func parallelMap<R>(striding n: Int, f: @escaping (Element) -> R, completion: @escaping ([R]) -> ()) {
        let N = self.count

        let res = UnsafeMutablePointer<R>.allocate(capacity: N)

        DispatchQueue.concurrentPerform(iterations: N/n) { k in
            for i in (k * n)..<((k + 1) * n) {
                res[i] = f(self[i])
            }
        }

        for i in (N - (N % n))..<N {
            res[i] = f(self[i])
        }

        let finalResult = Array<R>(UnsafeBufferPointer(start: res, count: N))
        res.deallocate(capacity: N)

        DispatchQueue.main.async {
            completion(finalResult)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Martin的版本避免了额外的副本,因为他有一个"零"值来初始化数组.如果你知道你的类型有一个小问题init(),你可以避免额外的副本:

protocol TriviallyInitializable {
    init()
}

extension Array {
    func parallelMap<R>(striding n: Int, f: @escaping (Element) -> R, completion: @escaping ([R]) -> ()) where R: TriviallyInitializable {
        let N = self.count

        var finalResult = Array<R>(repeating: R(), count: N)

        finalResult.withUnsafeMutableBufferPointer { res in
            DispatchQueue.concurrentPerform(iterations: N/n) { k in
                for i in (k * n)..<((k + 1) * n) {
                    res[i] = f(self[i])
                }
            }
        }

        for i in (N - (N % n))..<N {
            finalResult[i] = f(self[i])
        }

        DispatchQueue.main.async {
            completion(finalResult)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)