2016-01-02 113 views
1

在Web服務器上,許多線程正在將內容提供給客戶端。 A/B測試是在網站上執行的,所以我們需要PRNG爲每個會話和測試選擇一個變體。 顯然,當使用PRNG的單個實例時,它將被同時訪問,因此可能需要適當的鎖定或其他機制。Java中的併發隨機數生成

最初我們使用java.util.Random(juR),但由於它有缺陷提到例如How good is java.util.Random,我們試着用MersenneTwister代替。 然而,由於Mersenne-Twister relies on an internal state這一事實,我們看到性能大幅下降,所以它需要同步nextInt()的訪問權限。 另一種選擇可能是異或移位PRNG,但它與Mersenne Twister具有相同的問題。 你可以找到一個解釋,例如這裏:http://xorshift.di.unimi.it/

Randomuses a compareAndSet操作,它似乎更快,因爲它不需要鎖定,但根據類Javadoc它仍然不是線程安全的。相反,建議使用ThreadLocalRandom,這基本上會導致PRNG池。根據請求,隨機可用線程處理HTTPS請求,因此從一組可用的PRNG中選擇一個隨機PRNG。顯然這很快。

從這樣的池中產生的隨機數與單個PRNG實例中的一樣好嗎?

另一種方法是使用單個PRNG實例從它預先生成一個值流,例如,通過使用ArrayBlockingQueue

哪種解決方案在性能方面效果更好?

+1

對於這個應用程序(選擇A或B是否顯示給用戶),只要它們是均勻分佈的,隨機數的質量並不重要。 – Henry

+3

您正在預先優化。 Random被記錄爲線程安全的,並且與Web應用程序所需的所有IO(數據庫查詢,HTTP請求等)相比,每次啓動會話時調用nextBoolean()的性能完全可以忽略不計。 –

+0

這個想法試圖在隨機數質量方面提出比java.util.Random更好的東西。實際上我們不止有兩個變體,所以我們繪製整數。 @Henry據我所讀,Random中位數的概率並不是均勻分佈的。 – user3001

回答

2

爲了避免同步問題,每個線程都有一個RNG。爲避免線程特定的RNG給出相同的輸出,請讓主RNG爲線程特定的RNG生成一系列初始種子。這可能需要一個額外的種子參數傳入你的代碼來生成一個新的線程。

您需要爲自己測試RNG的不同選項在套件上的運行速度。如果需要,可以爲主RNG和線程特定的RNG使用不同的RNG引擎。一般情況下,爲線程特定的RNG選擇一個快速建立時間的RNG。這對於主RNG來說並不重要,因爲它只設置一次。

3

您可以通過將結果傳遞給BlockingQueue來使任何隨機數生成器線程安全。

class SafeRandom implements Runnable { 

    Random r = new Random(); 
    BlockingQueue<Double> q = new ArrayBlockingQueue<>(10); 

    double get() throws InterruptedException { 
     return q.take(); 
    } 

    @Override 
    public void run() { 
     try { 
      while (true) { 
       q.put(r.nextDouble()); 
      } 
     } catch (InterruptedException ie) { 
     } 
    } 

}