2012-04-05 95 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))