Shell

如何避免重複隨機數生成?

  • August 6, 2022

TL;博士

一個程序在同時啟動兩次時繪製相同的隨機種子。這是怎麼發生的?

細節

我正在執行 MCMC 統計分析,因此我執行程序 (phylobayes) 兩次以獲得2 個獨立複製。

為此,我的 shell 腳本分離每個複制執行,如下所示(示意性地):

pb -d "inputdata" "replicate1" &
pid1=$!

pb -d "inputdata" "replicate2" &
pid2=$!

wait "$pid1"
wait "$pid2"

(然後,使用 slurm 將此腳本送出到計算集群(Debian 10)sbatch)。

但我的許多執行(如 30%)都是從相同的隨機種子開始的!如日誌文件所示。

Phylobayes使用 C++Random::initRandom()命令。[**編輯:**實際上,正如所指出的,這個函式在包內有一個自定義定義]。

**從技術上講,是否可以採用相同的隨機種子?**它使用 /dev/random 還是 /dev/urandom ?

如果是,我將sleep在開始之間插入一個命令;

如果不是,我必須明白我犯了什麼愚蠢的錯誤,但我不明白它會是什麼……

從技術上講,是否可以採用相同的隨機種子?

如果您查看連結的函式,您會看到它使用微秒數作為種子(模 10^6):

void Random::InitRandom(int seed)   {

   if (seed == -1) {
       struct timeval tod;
       gettimeofday(&tod, NULL);
       seed = tod.tv_usec; // <== this line
   }
   Seed = seed;
   srand(seed);
   ...
}

所以,是的,如果您的軟體的兩個實例在同一微秒內執行該功能(或者可能恰好相差 1 秒等),您將獲得相同的種子。這是合理的,因為您會立即啟動一個實例。

gettimeofday() 通常具有比 1 μs 更粗的粒度這一事實進一步加劇了這種情況,因此時間上彼此非常接近的執行可能具有相同的 tv_usec 值,即使它們沒有發生在完全相同的微秒內。

我認為解決此問題的最佳方法是使用適合您使用軟體的方式的不同種子初始化算法建構您自己的版本。例如,您可以在每次後續執行時將種子數增加 1,或者使用 /dev/random,而不是使用微秒。

或者,如果您有 GNU coreutils,您可以使用該sleep 0.001命令將第二次執行暫停 1 毫秒,這應該會引入足以讓不同實例擁有不同種子的延遲。

引用自:https://unix.stackexchange.com/questions/712509