从/ dev / {random,urandom}生成快速并行随机数

时间:2014-05-11 11:05:30

标签: c multithreading random openmp

我的科研代码如下:

    #define TRIALS 1000000
    #define LEN 10
    int i;
    for(i=0;i<TRIALS;i++) {
        uint8_t r[LEN];
        getRand(r, LEN);
        doExperiment(r);
    }

我使用/ dev / urandom获取随机数:

    void getRand(uint8_t *r, int len) {
        int rand = open("/dev/urandom", O_RDONLY);
        read(rand, r, len);
        close(rand);
    }

注意:我不要求我的实验是可重复的,所以不要关心固定的种子。但是,任务关键,我的随机数是高质量的(合理地接近加密安全),因此我的结果的统计数据是有效的。速度也很重要。

我计划将此代码并行化,首先使用OpenMP,只需在我的循环前面加上#pragma omp parallel for即可。

问题:同时生成随机数的最佳方法是什么(建议不要使用/ dev / urandom)?我应该在调用getRand()时使用互斥量并允许我的代码序列化获取随机数,我是否应该尝试预先生成我需要的所有随机数,或者我应该有一个单独的线程来填充随机缓冲区以生产者 - 消费者的方式从(使用互斥锁)读取的数字?如果我使用/ dev / random代替最好的解决方案,这是一个有限的资源并且可能会阻塞?

我已阅读有关并行生成随机数的相关文章,但希望特别针对使用/ dev / {urandom,random}提出问题。

1 个答案:

答案 0 :(得分:0)

巩固一些评论......

对从/ dev / urandom读取的getRand()函数进行多次调用很慢并且应该避免,因为它使用会增加大量开销的系统调用。最好从/ dev / urandom读取更大的块并缓冲它们,或者使用/ dev / urandom来播种软件PRNG。

在后一种情况下,可以使用OpenSSL的RAND_bytes()返回“加密强随机”值。这可以配置为通过RDRAND指令使用英特尔的DRNG(参见http://wiki.openssl.org/index.php/Random_Numbers#Hardware),讨论here。这实际上是通过AES-NI指令集(也可以通过OpenSSL's EVP API直接访问)在计数器模式下使用AES的硬件实现。 According to Intel支持RDRAND的OpenSSL版本的性能比非RDRAND版本高出一个数量级。

用于为多个线程生成随机数的两种方法(在this post中讨论)要么为/ dev / urandom中的每个线程播种单独的PRNG,要么从/ dev / urandom中播种一个PRNG然后播种每个线程的PRNG来自那个。

但应该注意, OpenSSL不是线程安全的This post给出了一个使用OpenSSL和OpenMP的好例子。