我的科学研究代码如下所示:
#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/random 是有限的资源并且可能会阻塞?
我已经阅读了有关并行生成随机数的相关帖子,但希望专门解决一个与使用/dev/{urandom,random} 相关的问题。
最佳答案
整合一些评论...
多次调用从/dev/urandom 读取的 getRand()
函数速度很慢,应该避免,因为它使用系统调用,会增加大量开销。最好从/dev/urandom 读取更大的 block 并缓冲它们,或者使用/dev/urandom 来播种软件 PRNG。
在后一种情况下,可以使用 OpenSSL 的 RAND_bytes()
来返回“加密强随机”值。这可以配置为通过 RDRAND 指令使用 Intel 的 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 结合使用的一个很好的示例。
关于c - 来自/dev/{random,urandom} 的快速并行随机数生成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23591801/