How do I create and pass rng’s to a multi-threaded loop safely? For example, the following code will fail with large K.
function thread_samples(K)
rng = MersenneTwister(1)
samples = zeros(Int64, K)
Threads.@threads for k = 1:K
samples[k] = rand(rng, 1:10)
end
end
thread_samples(100000)
ERROR: LoadError: TaskFailedException:
InexactError: check_top_bit(UInt64, -88)
Stacktrace:
[1] throw_inexacterror(::Symbol, ::Type{UInt64}, ::Int64) at ./boot.jl:558
[2] check_top_bit at ./boot.jl:572 [inlined]
[3] toUInt64 at ./boot.jl:683 [inlined]
[4] UInt64 at ./boot.jl:713 [inlined]
[5] convert at ./number.jl:7 [inlined]
[6] cconvert at ./essentials.jl:388 [inlined]
[7] unsafe_copyto! at ./array.jl:245 [inlined]
[8] _rand_max383!(::MersenneTwister, ::Random.UnsafeView{Float64}, ::Random.CloseOpen12{Float64}) at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.5/Random/src/RNGs.jl:452
[9] rand!(::MersenneTwister, ::Random.UnsafeView{Float64}, ::Random.SamplerTrivial{Random.CloseOpen12{Float64},Float64}) at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.5/Random/src/RNGs.jl:486
[10] rand! at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.5/Random/src/Random.jl:266 [inlined]
[11] rand!(::MersenneTwister, ::Random.UnsafeView{UInt128}, ::Random.SamplerType{UInt128}) at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.5/Random/src/RNGs.jl:567
[12] rand! at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.5/Random/src/RNGs.jl:590 [inlined]
[13] rand! at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.5/Random/src/Random.jl:267 [inlined] (repeats 2 times)
[14] mt_setfull! at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.5/Random/src/RNGs.jl:215 [inlined]
[15] reserve1 at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.5/Random/src/RNGs.jl:222 [inlined]
[16] mt_pop! at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.5/Random/src/RNGs.jl:227 [inlined]
[17] rand at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.5/Random/src/RNGs.jl:392 [inlined]
[18] rand at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.5/Random/src/Random.jl:256 [inlined]
[19] rand(::MersenneTwister, ::Random.SamplerRangeNDL{UInt64,Int64}) at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.5/Random/src/generation.jl:326
[20] rand at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.5/Random/src/Random.jl:253 [inlined]
[21] macro expansion at /Users/mfairley/Projects/AdaptiveSurveillance/test/test_threaded_rng.jl:11 [inlined]
[22] (::var"#2#threadsfor_fun#1"{MersenneTwister,Array{Int64,1},UnitRange{Int64}})(::Bool) at ./threadingconstructs.jl:81
[23] (::var"#2#threadsfor_fun#1"{MersenneTwister,Array{Int64,1},UnitRange{Int64}})() at ./threadingconstructs.jl:48
Stacktrace:
[1] wait at ./task.jl:267 [inlined]
[2] threading_run(::Function) at ./threadingconstructs.jl:34
[3] macro expansion at ./threadingconstructs.jl:93 [inlined]
[4] thread_samples(::Int64) at /Users/mfairley/Projects/AdaptiveSurveillance/test/test_threaded_rng.jl:10
[5] top-level scope at /Users/mfairley/Projects/AdaptiveSurveillance/test/test_threaded_rng.jl:15
[6] include(::Function, ::Module, ::String) at ./Base.jl:380
[7] include(::Module, ::String) at ./Base.jl:368
[8] exec_options(::Base.JLOptions) at ./client.jl:296
[9] _start() at ./client.jl:506
in expression starting at /Users/mfairley/Projects/AdaptiveSurveillance/test/test_threaded_rng.jl:15
EDIT:
Is this the best way?
function thread_samples(K)
rng = [MersenneTwister(i) for i = 1:Threads.nthreads()]
samples = zeros(Int64, K)
Threads.@threads for k = 1:K
samples[k] = rand(rng[Threads.threadid()], 1:10)
end
end