urandomで乱数生成

Unixオペレーティングシステムの場合, スペシャルファイルとして/dev/random, /dev/urandomがある. これは一種のハードウェア乱数生成器として働く.
Pythonではos.urandomという関数があり, 引数にサイズを指定すると/dev/urandomからデータを引っ張ってきてくれる. 乱数の種を生成するのには, これを用いると良い.

import os
import binascii
myseed = int(binascii.hexlify(os.urandom(8)), 16)
myrandom.seed(myseed)

実際, Pythonのrandomでは自動的に同じことを行っている. ただし, OSがurandomに対応していない場合は, time.time()を用いているようだ.
しかしながら, /dev/urandomは読み出す際にロックされないため, これでも完璧ではない(同時に参照すると同じ値が返ってくる可能性がある). /dev/randomは読み出される度に次の乱数がプールされるまでロックされるため, このような問題を防ぐ.
僕はクラスタマシンで各ノードに固有のランダムシードを生成したいと考えていたのだが, urandomでも時々かぶることがある*1. 結局, ホストノードで/dev/urandomで乱数列を生成し, これをジョブの引数として投げることにした. 注意すべきこととしては, 当然だが, ホストで/dev/urandomで乱数を得て, それをシードとしした乱数列を生成してはいけない. ジョブに投げるシードの乱数列はすべて/dev/urandomから得ること.

*1:同じノードの別のCPUコアに同時にジョブが投げられているため, 同じデバイスを参照していることから起こるらしい.