Swift 3 Parallel for/地图循环 [英] Swift 3 Parallel for/map Loop

查看:78
本文介绍了Swift 3 Parallel for/地图循环的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对此有很多线程,但是使用Swift< 3.0代码,而我无法在3中使用等效代码(请参见代码). 使用GCD并行处理数组使用指针而且它有点难看,所以我要在这里断言我正在寻找好的Swift 3 方法(当然要尽可能高效).我还听说小组很慢(?),也许有人可以确认这一点.我也无法让小组一起工作.

There's quite a few threads on this however Using Grand Central Dispatch in Swift to parallelize and speed up "for" loops? uses Swift <3.0 code and I can't get the equivalent to work in 3 (see code). Process Array in parallel using GCD uses pointers and it gets a bit ugly so I'm going to assert right here that I'm looking for the nice Swift 3 way to do it (as efficiently as possible of course). I also heard groups are slow (?) maybe someone can confirm that. I couldn't get groups to work either.

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

Here is my implementation of a striding parallel map function (in an extension of Array). It want's to execute on the global queue so as to not block the UI. It may be that the concurrent bit doesn't need to be in the scope, only the remainder loop.

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!}
    }
}

错误1:内部阵列分配行上的老朋友EXC_BAD_ACCESS大约是我测试它的一半.我猜这暗示了同时访问问题.

Error 1: our old friend EXC_BAD_ACCESS on the inner array assignment line about half the times I test it. I'm guessing this suggests a simultaneous access issue.

错误2:completion从不执行!

错误3:错误永远存在,我敢肯定,一旦解决上述问题,这种错误就会发生.

Error 3: errors go on forever, I'm sure this will happen once the above are fixed.

最后:最快的并行代码(确保尽可能并行,我不喜欢代码中的并行")映射/函数.这是除修正我的代码之外的.

Finally: code for the fastest parallel (making sure it's as parallel as possible, I don't like the 'concurrent' in my code) map/for function possible. This is in addition to fixing my code.

推荐答案

马丁的原始方法仍然是正确的方法.将您的方法与他的方法合并并转换为Swift 3相当简单(尽管我摆脱了您的可选方法,只是手动处理了内存).

Martin's original approach is still the right way to do this. Merging your approach with his and converting to Swift 3 is fairly straightforward (though I got rid of your optionals and just handled the memory by hand).

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

Martin的版本避免了多余的副本,因为他有一个零"值来初始化数组.如果您知道您的类型具有琐碎的init(),则可以避免多余的副本:

Martin's version avoids the extra copy because he has a "zero" value to initialize the array to. If you know your type has a trivial init(), you can avoid the extra copy:

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

这篇关于Swift 3 Parallel for/地图循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆