Julia 1.5.2 并行启动随机数选择
Julia 1.5.2 Initiating random number selection in parallel
我目前正在尝试 运行 我的代码并行。我的部分代码(遗传算法)依赖于随机数的选择。因此,我需要确保使用的每个线程都有自己的随机数生成器。我还必须能够复制结果。因此,我“借用”了一个函数,它可以为每个线程设置随机种子或创建特定种子。
为了测试这是否正常工作,我想为每个线程设置相等的种子并测试是否生成了相同的随机数。然而,事实并非如此!
我认为我遗漏了有关数字生成的一些基本知识。创建随机数生成器时,我使用了相同的 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()]
对象的访问模式同上。请注意,在每种情况下,您都需要为每个线程保留一个单独的随机状态。出于性能原因(而不是多个线程竞争单个随机状态),也推荐使用这种方法。
我目前正在尝试 运行 我的代码并行。我的部分代码(遗传算法)依赖于随机数的选择。因此,我需要确保使用的每个线程都有自己的随机数生成器。我还必须能够复制结果。因此,我“借用”了一个函数,它可以为每个线程设置随机种子或创建特定种子。
为了测试这是否正常工作,我想为每个线程设置相等的种子并测试是否生成了相同的随机数。然而,事实并非如此!
我认为我遗漏了有关数字生成的一些基本知识。创建随机数生成器时,我使用了相同的 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()]
对象的访问模式同上。请注意,在每种情况下,您都需要为每个线程保留一个单独的随机状态。出于性能原因(而不是多个线程竞争单个随机状态),也推荐使用这种方法。