Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make the random module thread-safe in Python

I have an application requiring the same results given the same random seed. But I find random.randint not threadsafe. I have tried mutex but this does not work. Here is my experiment code (long but simple):

import threading
import random

def child(n, a):
    g_mutex = threading.Lock()
    g_mutex.acquire()
    random.seed(n)
    for i in xrange(100):
        a.append(random.randint(0, 1000))
    g_mutex.release()

def main():
    a = []
    b = []
    c1 = threading.Thread(target = child, args = (10, a))
    c2 = threading.Thread(target = child, args = (20, b))
    c1.start()
    c2.start()
    c1.join()
    c2.join()

    c = []
    d = []
    c1 = threading.Thread(target = child, args = (10, c))
    c2 = threading.Thread(target = child, args = (20, d))
    c1.start()
    c1.join()
    c2.start()
    c2.join()

    print a == c, b == d

if __name__ == "__main__":
    main()

I want to code to print true, true, but it stands a chance to give false, false. How can I make threadsafe randint?

like image 576
onemach Avatar asked Apr 05 '12 02:04

onemach


People also ask

Is random thread-safe?

Yes, Random is thread safe. the nextInt() method calls the protected next(int) method which uses AtomicLong seed, nextseed (atomic long) to generate a next seed. AtomicLong is used for thread-safety upon seed generation.

What is thread-safe in Python?

Thread safety is a concept that describes work with multithreaded programs. Code is considered to be thread-safe if it can work normally with multiple threads. For example, print function is not thread-safe.

Is Python file write thread-safe?

You can write to file in a thread-safe manner using a mutex lock via the threading.


2 Answers

You can create separate instances of random.Random for each thread

>>> import random
>>> local_random = random.Random()
>>> local_random.seed(1234)
>>> local_random.randint(1,1000)
967
like image 135
John La Rooy Avatar answered Oct 04 '22 19:10

John La Rooy


From the documentation for random:

The functions supplied by this module are actually bound methods of a hidden instance of the random.Random class. You can instantiate your own instances of Random to get generators that don’t share state. This is especially useful for multi-threaded programs, creating a different instance of Random for each thread, and using the jumpahead() method to make it likely that the generated sequences seen by each thread don’t overlap.

The documentation doesn't say exactly what this class is, but it does show class random.SystemRandom([seed]), and random.Random([seed]) seems to be the same.

Example:

local_random = random.Random(n)
for i in xrange(100):
    a.append(local_random.randint(0, 1000))
like image 40
Brendan Long Avatar answered Oct 04 '22 20:10

Brendan Long