Swift中的多线程函数式编程 [英] Multithreaded Functional Programming in Swift

查看:80
本文介绍了Swift中的多线程函数式编程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近我一直在Swift 2.1中操作字节数组,我经常发现自己正在编写如下代码:

I've been manipulating byte arrays in Swift 2.1 lately, and I often find myself writing code like this:

// code to add functions to a [UInt8] object
extension CollectionType where Generator.Element == UInt8 {

    func xor(with byte: UInt8) -> [UInt8] {
        return map { $0 ^ byte }
    }
}

// example usage: [67, 108].xor(with: 0) == [67, 108]

是否有一种简便的方法可以并行化此map调用,以便多个线程可以同时在数组的非重叠区域上操作?

Is there an easy way to parallelize this map call, so that multiple threads can operate on non-overlapping areas of the array at the same time?

我可以编写代码以手动将数组划分为子数组,并在不同线程中的每个子数组上调用map. 但是我想知道Swift中是否存在一些框架来自动进行除法,因为map是一个函数调用,可以在线程安全的环境中工作而没有副作用.

I could write code to manually divide the array into sub-arrays and call map on each sub-array in distinct threads. But I wonder if some framework exists in Swift to do the division automatically, since map is a functional call that can work in a thread-safe environment without side-effects.

澄清说明:

  1. 代码仅需要在[UInt8]对象上工作,而不必在每个CollectionType对象上工作.
  1. The code only needs to work on a [UInt8] object, not necessarily every CollectionType.

推荐答案

并行执行计算循环的最简单方法是concurrentPerform(以前称为并发编程指南中的/OperationQueues/OperationQueues.html#//apple_ref/doc/uid/TP40008091-CH102-SW23"rel =" nofollow noreferrer>同时执行循环迭代.但是,不,没有map格式版本可以为您完成此操作.你必须自己做.

The easiest way to perform a loop of calculations in parallel is concurrentPerform (previously called dispatch_apply; see Performing Loop Iterations Concurrently in the Concurrency Programming Guide). But, no, there is no map rendition that will do this for you. You have to do this yourself.

例如,您可以编写扩展来执行并发任务:

For example, you could write an extension to perform the concurrent tasks:

extension Array {

    public func concurrentMap<T>(_ transform: (Element) -> T) -> [T] {
        var results = [Int: T]()

        let queue = DispatchQueue(label: Bundle.main.bundleIdentifier! + ".sync", attributes: .concurrent)

        DispatchQueue.concurrentPerform(iterations: count) { index in
            let result = transform(self[index])
            queue.async { results[index] = result }
        }

        return queue.sync(flags: .barrier) {
            (0 ..< results.count).map { results[$0]! }
        }
    }

}

注意:

  • 这将阻止您从中调用它的线程(就像非并发的map一样),因此请确保将其分派到后台队列.

  • This will block the thread you call it from (just like the non-concurrent map will), so make sure to dispatch this to a background queue.

需要确保每个线程上有足够的工作来证明管理所有这些线程的固有开销. (例如,每个循环仅进行一个xor调用是不够的,您会发现它实际上比非并行再现慢.)在这些情况下,请确保大步前进(请参阅

One needs to ensure that there is enough work on each thread to justify the inherent overhead of managing all of these threads. (E.g. a simple xor call per loop is not sufficient, and you'll find that it's actually slower than the non-concurrent rendition.) In these cases, make sure you stride (see Improving Loop Code that balances the amount of work per concurrent block). For example, rather than doing 5000 iterations of one extremely simple operation, do 10 iterations of 500 operations per loop. You may have to experiment with suitable striding values.

虽然我怀疑您不需要进行讨论,但对于不熟悉concurrentPerform(以前称为dispatch_apply)的读者,我将在下面说明其用法.有关该主题的更完整讨论,请参考上面的链接.

While I suspect you don't need this discussion, for readers unfamiliar with concurrentPerform (formerly known as dispatch_apply), I'll illustrate its use below. For a more complete discussion on the topic, refer to the links above.

例如,让我们考虑比简单的xor复杂得多的东西(由于简单的东西,开销超过了所获得的任何性能),例如朴素的Fibonacci实现:

For example, let's consider something far more complicated than a simple xor (because with something that simple, the overhead outweighs any performance gained), such as a naive Fibonacci implementation:

func fibonacci(_ n: Int) -> Int {
    if n == 0 || n == 1 {
        return n
    }
    return fibonacci(n - 1) + fibonacci(n - 2)
}

如果要计算的值为Intarray,而不是:

If you had an array of Int values for which you wanted to calculate, rather than:

let results = array.map { fibonacci($0) }

您可以:

var results = [Int](count: array.count, repeatedValue: 0)
DispatchQueue.concurrentPerform(iterations: array.count) { index in
    let result = self.fibonacci(array[index])
    synchronize.update { results[index] = result }      // use whatever synchronization mechanism you want
}

或者,如果您想进行功能演绎,则可以使用上面定义的extension:

Or, if you want a functional rendition, you can use that extension I defined above:

let results = array.concurrentMap { fibonacci($0) }


有关Swift 2再现,请参见此答案的先前版本.

这篇关于Swift中的多线程函数式编程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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