Why is this line like this in Base.Random?

The Base.Random implementation of per-thread global RNGs seems to be a pattern for thread-safe mutations in Julia. I’m trying to implement something similar for a problem that strongly benefits from caching intermediate results for future calls to use.

However, I don’t understand the reasoning behind the one line in the __init__() function. Here’s the Base.Random.RNGs source from master,

const THREAD_RNGs = MersenneTwister[]
@inline default_rng() = default_rng(Threads.threadid())
@noinline function default_rng(tid::Int)
    0 < tid <= length(THREAD_RNGs) || _rng_length_assert()
    if @inbounds isassigned(THREAD_RNGs, tid)
        @inbounds MT = THREAD_RNGs[tid]
        MT = MersenneTwister()
        @inbounds THREAD_RNGs[tid] = MT
    return MT
@noinline _rng_length_assert() =  @assert false "0 < tid <= length(THREAD_RNGs)"

function __init__()
    resize!(empty!(THREAD_RNGs), Threads.nthreads()) # ensures that we didn't save a bad object

My naive approach would have been to write an __init__() which creates nthreads() copies of MersenneTwister(). Why is it preferable to fill an array with undef?

1 Like

In my understanding, it’s to reduce load time. Creating a MersennTwister is not free, so creating nthreads() copies of it unconditionally even when they are not needed is a waste of resources. One goal is to make julia startup as fast as possible.


Creating all the RNG on the same thread was measurably slower due to false sharing.


Thank you, that makes a lot of sense.