# Random number flow independent from the number of threads

**URL:** <https://discourse.julialang.org/t/random-number-flow-independent-from-the-number-of-threads/57850>\
**Category:** General Usage\
**Tags:** question, multithreading, random\
**Created:** [March 24, 2021, 8:17am UTC](https://discourse.julialang.org/t/random-number-flow-independent-from-the-number-of-threads/57850 "2021-03-24T08:17:40Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![sylvaticus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sylvaticus/32/203883_2.png) [@sylvaticus](https://discourse.julialang.org/u/sylvaticus)\
**Post date:** [March 24, 2021, 8:17am UTC](https://discourse.julialang.org/t/random-number-flow-independent-from-the-number-of-threads/57850/1 "2021-03-24T08:17:40Z")

</div>

I am still trying to arrive to a workflow where I can set some multithreaded experiment random or fixed given some input depending of the needs.

The code above works for a given (fixed) number of threads, but if I let change the number of threads only the `MersenneTwister` implementation remains constant, while the `StableRNG` implementation returns an output that depends on the number of threads used. Do you know any workaround I could use ? I would like to keep using StableRNGs to keep my unit tests and output results independent on the specific Julia version.

```julia
using Random, StableRNGs, Statistics

function generateParallelRngs(rng::AbstractRNG, n::Integer)
    seeds = [rand(rng,100:18446744073709551615) for i in 1:n] # some RNGs have issues with too small seeds
    rngs = [deepcopy(rng) for i in 1:n]
    return Random.seed!.(rngs,seeds)
end

function myFunction(rng = Random.GLOBAL_RNG)
    rngs = generateParallelRngs(rng,Threads.nthreads()) # make new copy instances
    results = Array{Float64,1}(undef,30)
    masterSeed = rand(rng,100:9999999999999)
    Threads.@threads for i in 1:30
        tsrng = rngs[Threads.threadid()] # Thread safe random number generator: one RNG per thread
        Random.seed!(tsrng,masterSeed+i*10) # Here we let the seed depends on the i of the loop, not the thread: we get same results indipendently of the number of threads
        results[i] = sum(rand(tsrng, 1:1000,100))
    end
    overallResult = mean(results)
    return overallResult
end

myFunction(MersenneTwister(123)) # same result whatever the number of threads
myFunction(MersenneTwister(123)) # always same as previous line, as expected
myFunction(StableRNG(123)) # output depends on number of threads (i.e. `julia -t 2` ≠ `julia -t 4` outputs)
myFunction(StableRNG(123)) # always same as previous line, as expected

```

---

<div class="post-metadata">

**Author:** ![sylvaticus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sylvaticus/32/203883_2.png) [@sylvaticus](https://discourse.julialang.org/u/sylvaticus)\
**Post date:** [March 24, 2021, 8:45am UTC](https://discourse.julialang.org/t/random-number-flow-independent-from-the-number-of-threads/57850/2 "2021-03-24T08:45:35Z")

</div>

Just discovered that doing the master seeding _before_ the `generateParallelRngs` solved the issue, but I still wonder why, and why the issue is only with the StableRNG…  
EDIT: I’m an idiot. Of course `rand` in `generateParallelRngs` is called proportionally to the number of threads, so if I call rand again later, its output will depend on the number of threads. Now the question is the opposite: why the `MersenneTwister` implementation didn’t change…

---

<div class="post-metadata">

**Author:** ![rfourquet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rfourquet/32/3610_2.png) [@rfourquet](https://discourse.julialang.org/u/rfourquet)\
**Post date:** [March 24, 2021, 9:19am UTC](https://discourse.julialang.org/t/random-number-flow-independent-from-the-number-of-threads/57850/3 "2021-03-24T09:19:10Z")

</div>

> [@sylvaticus](#):
>
> Now the question is the opposite: why the `MersenneTwister` implementation didn’t change…

It’s because generating a range of `Int64` or of `Int128` use different “caches” (arrays of ready-to-be-fetched random values) within a `MersenneTwister`. I.e, whether you use 2 or 4 values from say `cache1`, it doesn’t affect the state (next available value) of `cache2`.

---

<div class="post-metadata">

**Author:** ![greg\_plowman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/greg_plowman/32/8100_2.png) [@greg\_plowman](https://discourse.julialang.org/u/greg_plowman)\
**Post date:** [March 24, 2021, 8:50pm UTC](https://discourse.julialang.org/t/random-number-flow-independent-from-the-number-of-threads/57850/4 "2021-03-24T20:50:20Z")

</div>

> [@sylvaticus](#):
>
> Just discovered that doing the master seeding _before_ the `generateParallelRngs` solved the issue, but I still wonder why, and why the issue is only with the StableRNG…

Moreover, if you are re-seeding in each iteration, then there’s no point in seeding in `generateParallelRngs`.
