7

在给定相同随机种子的情况下,我有一个应用程序需要相同的结果。但我发现 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()

我想编写代码来打印true, true,但它有机会给出false, false。我怎样才能使线程安全randint?

4

3 回答 3

24

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

>>> import random
>>> local_random = random.Random()
>>> local_random.seed(1234)
>>> local_random.randint(1,1000)
967
于 2012-04-05T02:30:28.127 回答
11

文档中random

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

文档没有确切说明这个类是什么,但它确实显示了class random.SystemRandom([seed]),并且random.Random([seed])似乎是一样的。

例子:

local_random = random.Random(n)
for i in xrange(100):
    a.append(local_random.randint(0, 1000))
于 2012-04-05T02:30:55.010 回答
5

其他人指出了以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()

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

编辑

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

于 2012-04-05T02:35:55.630 回答