2012-04-05 41 views
3

我有一个应用程序在给定相同的随机种子时需要相同的结果。但是我发现random.randint不是线程安全的。我试过互斥体,但这不起作用。这里是我的实验代码(长,但简单):在Python中使随机模块线程安全

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

我希望将代码打印真实,真实,但它代表一个机会给假的,假的。我如何制作线程安全的randint?

回答

3

其他人则指出了一个线程安全的方式使用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分配一个值。

编辑

我只想补充一点,简单地切换到全局锁不能保证你说该怎么做。该锁将确保一次只有一个线程正在生成数字,但不能保证哪个线程将首先启动。

+0

不敢相信我没注意到。如果你持有一个全局锁,那不是线程中有太多要点。 – 2012-04-05 02:37:04

13

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

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

the documentation for 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))