Julia多线程循环内设置随机种子实现结果可复现的问题咨询
问题原因
Julia的默认随机数生成器为线程本地实例,你调用的Random.seed!(1234)仅会设置当前主线程的随机种子,其余工作线程的随机种子仍为随机生成状态,因此多线程场景下每次运行结果无法复现。此外如果使用动态调度的多线程策略,就算所有线程种子固定,任务分配到线程的顺序变化也会导致结果不一致。
解决方案
这里提供两种常用的可复现多线程随机数生成方案:
方案1:固定所有线程的随机种子
适合使用Threads.@threads默认静态调度、不需要跨线程数保持结果一致的场景:
using Random # 为所有线程批量设置固定种子,种子取值保证每个线程唯一即可 Random.seed!.(1234 .+ 1:Threads.nthreads()) a = [Float64[] for _ in 1:Threads.nthreads()] Threads.@threads for i = 1:10 push!(a[Threads.threadid()], rand()) end sum(reduce(vcat, a))
方案2:每个任务绑定独立随机数生成器(更推荐)
该方案不受线程数量、调度策略影响,就算调整运行时的线程数,也能得到完全一致的结果:
using Random const N = 10 a = zeros(N) # 提前为每个任务预生成唯一的固定种子,也可以直接预生成RNG实例列表 task_seeds = 1234 .+ 1:N Threads.@threads for i in 1:N # Julia 1.7及以上版本推荐使用Xoshiro作为并行场景的RNG,性能和随机性表现更优 rng = Xoshiro(task_seeds[i]) a[i] = rand(rng) end sum(a)
如果需要在单任务内生成大量随机数,可提前在主线程预先生成所有任务对应的RNG实例列表,避免循环内重复创建开销。
内容的提问来源于stack exchange,提问作者Fabrizio Leone
相关产品推荐
相关产品推荐

