Julia 1.5.2 并行启动随机数选择

Julia 1.5.2 Initiating random number selection in parallel

我目前正在尝试 运行 我的代码并行。我的部分代码(遗传算法)依赖于随机数的选择。因此,我需要确保使用的每个线程都有自己的随机数生成器。我还必须能够复制结果。因此,我“借用”了一个函数,它可以为每个线程设置随机种子或创建特定种子。

https://discourse.julialang.org/t/how-do-i-deal-with-random-number-generation-when-multithreading/5636/2

为了测试这是否正常工作,我想为每个线程设置相等的种子并测试是否生成了相同的随机数。然而,事实并非如此!

我认为我遗漏了有关数字生成的一些基本知识。创建随机数生成器时,我使用了相同的 UInt32。因此,我认为他们应该绘制相同的数字,但是 randjump 可能会干扰这一点。也许随机数生成器不会“跳转”到同一个 point/state 以确保每个在循环中彼此足够远。也许他们这样做时共享一个状态?有没有办法控制实施是否准确?也许这里有更大的错误?

clearconsole()
using Test
using Random
using Future
using Test

function set_rngs(random_seed)
    if random_seed == true
        rng_seed = Random.make_seed()
        rng = MersenneTwister(rng_seed)
        return Future.randjump(rng, Threads.nthreads());
    else
        rng_seed = UInt32[0xbd8e7dc4,0xbd8e7dc4];
        rng = Random.MersenneTwister(rng_seed)
        return Future.randjump(rng, Threads.nthreads());
    end
end

function random_test()
    tmp = Vector{Float64}(undef, 100)

    Threads.@threads for i in 1:100
        tmp[i] = rand()
    end
    return tmp
end

Random.seed!(set_rngs(false))
tester = random_test()


function testing_rand(tester::Vector{Float64})
    @testset "Testing if random numbers drawn by each processer are different" begin
        for i in 1:50
            @test tester[i] != tester[i+50]
        end
    end
end

testing_rand(tester)

您基本上不需要使用 randjump,因为 MersenneTwister 流不相关。

因此,为线程启动随机流的标准方法如下:

using Random
const mts = MersenneTwister.(1:Threads.nthreads())

编写代码时,您总是通过以下方式访问适当的随机状态:

rand(mts[Threads.threadid()])

在极少数情况下,您可能确实希望拥有同一随机流的不同部分,并且需要执行 randjump.

const mts2 = [Future.randjump(MersenneTwister(0), i) for i in 1:Threads.nthreads()]

对象的访问模式同上。请注意,在每种情况下,您都需要为每个线程保留一个单独的随机状态。出于性能原因(而不是多个线程竞争单个随机状态),也推荐使用这种方法。