我已经阅读了与我要问的问题类似的问题,但是答案对我来说似乎并不完整或不完全清楚。
我正在尝试并行化参数扫描,该参数扫描需要重复生成一组随机数。目前,只有一个线程可以执行以下操作:
int main() {
//Get random number generators
typedef std::mt19937 MyRNG;
std::random_device rd;
//seed generator
MyRNG rng;
rng.seed(rd());
//make my uniform distributions for each parameter
std::uniform_real_distribution<> param1(-1,1);
std::uniform_real_distribution<> param2(-1,1);
double x,y;
//Do my scan
for (int i = 0; i < N; i++) {
x = param1(rng)
y = param2(rng)
//Do things with x and y*
}
这样,每次扫描都会得到一个新的x和y。现在,我想利用多个内核并行执行此操作。因此,我定义了一个函数void scan()
,该函数基本上与我的主要函数具有相同的内容。然后,我创建多个线程,每个线程都运行scan()
。但是我不确定使用std :: thread是否是线程安全的。我现在在每个线程中生成的随机数是否是独立的?我可以通过在void
函数之外创建我的RNG来节省时间吗?谢谢。
我可能会在main
中生成seeds,并将种子传递给每个线程函数。我也不会直接使用std::random_device
的输出-我将数字放到std::set
或std::unordered_set
之类的东西中,直到获得想要的种子数为止,以确保不会给两个线程相同的种子(这显然会浪费时间)。
这条基本思路:
int do_work(unsigned long long seed) {
//Get random number generators
typedef std::mt19937 MyRNG;
//seed generator
MyRNG rng(seed);
//make my uniform distributions for each parameter
std::uniform_real_distribution<> param1(-1,1);
std::uniform_real_distribution<> param2(-1,1);
double x,y;
//Do my scan
for (int i = 0; i < N; i++) {
x = param1(rng);
y = param2(rng);
//Do things with x and y*
}
}
static const int num_threads = 4;
int main() {
std::set<unsigned long long> seeds;
while (seeds.size() < num_threads)
seeds.insert(std::random_device()());
std::vector<std::thread> threads;
for (auto const seed: seeds)
threads.emplace_back(std::thread(do_work, seed));
for (auto &t : threads)
t.join();
}
此外,使用random_device
的单个结果作为std::mt19937
的种子会限制生成器的相当一部分-您只给它32(或可能是64)位种子,但实际上它有19937位种子材料。 std::seed_seq
尝试至少在某种程度上加以改善(除其他外,您可以使用std::random_device
的许多输出来创建种子。