在Swift中使用Grand Central Dispatch并行化并加快"for"操作的速度.循环? [英] Using Grand Central Dispatch in Swift to parallelize and speed up “for" loops?

查看:127
本文介绍了在Swift中使用Grand Central Dispatch并行化并加快"for"操作的速度.循环?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在努力解决如何使用GCD并行化和加速蒙特卡洛模拟的问题.大部分/所有简单的示例都是针对Objective C的,我确实需要一个Swift的简单示例,因为Swift是我的第一种真实"编程语言.

I am trying to wrap my head around how to use GCD to parallelize and speed up Monte Carlo simulations. Most/all simple examples are presented for Objective C and I really need a simple example for Swift since Swift is my first "real" programming language.

Swift中蒙特卡洛模拟的最低工作版本应如下所示:

The minimal working version of a monte carlo simulation in Swift would be something like this:

import Foundation

import Cocoa
var winner = 0
var j = 0
var i = 0
var chance = 0
var points = 0
for j=1;j<1000001;++j{
    var ability = 500

    var player1points = 0

    for i=1;i<1000;++i{
        chance = Int(arc4random_uniform(1001))
        if chance<(ability-points) {++points}
        else{points = points - 1}
    }
    if points > 0{++winner}
}
    println(winner)

代码可以直接粘贴到xcode 6.1的命令行程序项目中

The code works directly pasted into a command line program project in xcode 6.1

最内层的循环无法并行化,因为在下一个循环中使用了变量"points"的新值.但是最外面的只是将最里面的模拟运行了1000000次并计算出结果,因此它应该是并行化的理想选择.

The innermost loop cannot be parallelized because the new value of variable "points" is used in the next loop. But the outermost just run the innermost simulation 1000000 times and tally up the results and should be an ideal candidate for parallelization.

所以我的问题是如何使用GCD并行化最外层的for循环?

So my question is how to use GCD to parallelize the outermost for loop?

推荐答案

可以使用dispatch_apply()完成多线程迭代":

A "multi-threaded iteration" can be done with dispatch_apply():

let outerCount = 100    // # of concurrent block iterations
let innerCount = 10000  // # of iterations within each block

let the_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(UInt(outerCount), the_queue) { outerIdx -> Void in
    for innerIdx in 1 ... innerCount {
       // ...
    }
}

(您必须找出外部计数与内部计数之间的最佳关系.)

(You have to figure out the best relation between outer and inner counts.)

有两件事要注意:

  • arc4random() uses an internal mutex, which makes it extremely slow when called from several threads in parallel, see Performance of concurrent code using dispatch_group_async is MUCH slower than single-threaded version. From the answers given there, rand_r() (with separate seeds for each thread) seems to be faster alternative.

不得同时从多个线程修改结果变量winner. 您可以使用数组代替,其中每个线程都更新其自己的元素,并且结果 之后添加. https://stackoverflow.com/a/26790019/1187415 中已描述了线程安全方法.

The result variable winner must not be modified from multiple threads simultaneously. You can use an array instead where each thread updates its own element, and the results are added afterwards. A thread-safe method has been described in https://stackoverflow.com/a/26790019/1187415.

然后它将大致如下所示:

Then it would roughly look like this:

let outerCount = 100     // # of concurrent block iterations
let innerCount = 10000   // # of iterations within each block

let the_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

var winners = [Int](count: outerCount, repeatedValue: 0)
winners.withUnsafeMutableBufferPointer { winnersPtr -> Void in

    dispatch_apply(UInt(outerCount), the_queue) { outerIdx -> Void in
        var seed = arc4random() // seed for rand_r() in this "thread"

        for innerIdx in 1 ... innerCount {
            var points = 0
            var ability = 500

            for i in 1 ... 1000 {
                let chance = Int(rand_r(&seed) % 1001)
                if chance < (ability-points) { ++points }
                else {points = points - 1}
            }
            if points > 0 {
                winnersPtr[Int(outerIdx)] += 1
            }
        }
    }
}

// Add results:
let winner = reduce(winners, 0, +)
println(winner)

这篇关于在Swift中使用Grand Central Dispatch并行化并加快"for"操作的速度.循环?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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