使随机模块在Python中是线程安全的

时间:2021-04-08 21:01:53

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):

给定相同的随机种子,我有一个应用程序需要相同的结果。但我发现random.randint不是线程安全的。我尝试了互斥,但这不起作用。这是我的实验代码(长而简单):

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?

我想编码打印真实,真实,但它有机会给出虚假,虚假。我怎样才能制作线程安全的randint?

3 个解决方案

#1


3  

Others have pointed out the proper way to use random in a thread safe way. But I feel it's important to point out that the code you wrote would not be thread-safe for anything.

其他人已经指出了以线程安全的方式使用随机的正确方法。但我觉得重要的是要指出你编写的代码对任何东西都不是线程安全的。

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()

Each thread is running this method independently. That means that each thread is making their own lock instance, acquiring it, doing work, and then releasing it. Unless every thread is attempting to acquire the same lock, the there is nothing to ensure non-parallel execution. You need to assign a single value to g_mutex outside of the context of your run method.

每个线程都独立运行此方法。这意味着每个线程都在创建自己的锁实例,获取它,做工作,然后释放它。除非每个线程都试图获取相同的锁,否则没有什么可以确保非并行执行。您需要在run方法的上下文之外为g_mutex分配单个值。

Edit:

编辑:

I just want to add that simply switching to a global lock is not guaranteed to do exactly what you said. The lock will ensure that only one thread is generating numbers at a time, but it does not guarantee which thread will start first.

我只是想补充一点,简单地切换到全局锁并不能保证完全按照你所说的去做。锁定将确保一次只有一个线程生成数字,但不保证首先启动哪个线程。

#2


14  

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

您可以为每个线程创建random.Random的单独实例

>>> import random
>>> local_random = random.Random()
>>> local_random.seed(1234)
>>> local_random.randint(1,1000)
967

#3


7  

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.

该模块提供的函数实际上是random.Random类的隐藏实例的绑定方法。您可以实例化您自己的Random实例,以获取不共享状态的生成器。这对于多线程程序特别有用,为每个线程创建一个不同的Random实例,并使用jumpahead()方法使每个线程看到的生成序列可能不重叠。

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.

文档并没有准确说明这个类是什么,但它确实显示了类random.SystemRandom([seed])和random.Random([seed])似乎是相同的。

Example:

例:

local_random = random.Random(n)
for i in xrange(100):
    a.append(local_random.randint(0, 1000))

#1


3  

Others have pointed out the proper way to use random in a thread safe way. But I feel it's important to point out that the code you wrote would not be thread-safe for anything.

其他人已经指出了以线程安全的方式使用随机的正确方法。但我觉得重要的是要指出你编写的代码对任何东西都不是线程安全的。

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()

Each thread is running this method independently. That means that each thread is making their own lock instance, acquiring it, doing work, and then releasing it. Unless every thread is attempting to acquire the same lock, the there is nothing to ensure non-parallel execution. You need to assign a single value to g_mutex outside of the context of your run method.

每个线程都独立运行此方法。这意味着每个线程都在创建自己的锁实例,获取它,做工作,然后释放它。除非每个线程都试图获取相同的锁,否则没有什么可以确保非并行执行。您需要在run方法的上下文之外为g_mutex分配单个值。

Edit:

编辑:

I just want to add that simply switching to a global lock is not guaranteed to do exactly what you said. The lock will ensure that only one thread is generating numbers at a time, but it does not guarantee which thread will start first.

我只是想补充一点,简单地切换到全局锁并不能保证完全按照你所说的去做。锁定将确保一次只有一个线程生成数字,但不保证首先启动哪个线程。

#2


14  

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

您可以为每个线程创建random.Random的单独实例

>>> import random
>>> local_random = random.Random()
>>> local_random.seed(1234)
>>> local_random.randint(1,1000)
967

#3


7  

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.

该模块提供的函数实际上是random.Random类的隐藏实例的绑定方法。您可以实例化您自己的Random实例,以获取不共享状态的生成器。这对于多线程程序特别有用,为每个线程创建一个不同的Random实例,并使用jumpahead()方法使每个线程看到的生成序列可能不重叠。

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.

文档并没有准确说明这个类是什么,但它确实显示了类random.SystemRandom([seed])和random.Random([seed])似乎是相同的。

Example:

例:

local_random = random.Random(n)
for i in xrange(100):
    a.append(local_random.randint(0, 1000))