如何生成线程安全的统一随机数? [英] How do I generate thread-safe uniform random numbers?

查看:39
本文介绍了如何生成线程安全的统一随机数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的程序需要在某个范围内生成许多随机整数(int min,int max).每次调用都有一个不同的范围.什么是好的(最好是线程安全的)方法来做到这一点?以下不是线程安全的(并且使用了人们似乎不鼓励的 rand()):

My program needs to generate many random integers in some range (int min, int max). Each call will have a different range. What is a good (preferably thread-safe) way to do this? The following is not thread-safe (and uses rand(), which people seem to discourage):

int intRand(const int & min, const int & max)
{
    return (rand() % (max+1-min)) + min;
}

慢很多,但使用:

int intRand(const int & min, const int & max) {
    std::default_random_engine generator;
    std::uniform_int_distribution<int> distribution(min,max);
    return distribution(generator);
}

这样的事情就是我想要的(虽然 changeParameters 函数不存在):

Something like this is what I'm going for (the changeParameters function doesn't exist though):

int intRand(const int & min, const int & max) {
    static std::default_random_engine generator;
    static std::uniform_int_distribution<int> distribution(0, 10);
    distribution.changeParameters(min, max);
    return distribution(generator);
}

另一种选择是在 uniform_int_distribution 上做一个广泛的范围,然后像第一个例子一样使用 mod.但是,我正在做统计工作,所以我希望数字来自尽可能无偏的分布(例如,如果使用的分布范围不是 (max-min) 的倍数,分布将略微有偏见).这是一个选项,但同样,我想避免它.

Another option would be to make a wide range on the uniform_int_distribution and then use mod like in the first example. However, I'm doing statistical work, so I want the numbers to come from as unbiased of a distribution as possible (e.g., if the range of the distribution used is not a multiple of (max-min), the distribution will be slightly biased). This is an option, but again, I would like to avoid it.

解决方案 此解决方案来自 @konrad-rudolph @mark-ransom 和 @mathk 的答案.随机数生成器的播种是为了满足我的特定需求.更常见的方法是使用 time(NULL).如果您在同一秒内创建多个线程,那么它们将获得相同的种子.即使使用 clock() 这也是一个问题,所以我们包含线程 id.一个缺点 - 这会泄漏内存 --- 每个线程一个生成器.

SOLUTION This solution comes from the answers by @konrad-rudolph @mark-ransom and @mathk . The seeding of the random number generator is done to suit my particular needs. A more common approach would be to use time(NULL). If you make many threads in the same second, they would then get the same seed though. Even with clock() this is an issue, so we include the thread id. A drawback - this leaks memory --- one generator per thread.

#if defined (_MSC_VER)  // Visual studio
    #define thread_local __declspec( thread )
#elif defined (__GCC__) // GCC
    #define thread_local __thread
#endif

#include <random>
#include <time.h>
#include <thread>

using namespace std;

/* Thread-safe function that returns a random number between min and max (inclusive).
This function takes ~142% the time that calling rand() would take. For this extra
cost you get a better uniform distribution and thread-safety. */
int intRand(const int & min, const int & max) {
    static thread_local mt19937* generator = nullptr;
    if (!generator) generator = new mt19937(clock() + this_thread::get_id().hash());
    uniform_int_distribution<int> distribution(min, max);
    return distribution(*generator);
}

推荐答案

你试过了吗?

int intRand(const int & min, const int & max) {
    static thread_local std::mt19937 generator;
    std::uniform_int_distribution<int> distribution(min,max);
    return distribution(generator);
}

分布非常便宜(它们将被优化器完全内联,因此唯一剩余的开销是实际的随机数重新缩放).不要害怕根据需要经常重新生成它们 - 事实上,从概念上讲,重置它们并不便宜(这就是为什么不存在该操作的原因).

Distributions are extremely cheap (they will be completely inlined by the optimiser so that the only remaining overhead is the actual random number rescaling). Don’t be afraid to regenerate them as often as you need – in fact, resetting them would conceptually be no cheaper (which is why that operation doesn’t exist).

另一方面,实际的随机数生成器是一个重量级的对象,带有很多状态并且需要相当长的时间来构建,因此每个线程(甚至跨线程,但那么你就需要同步访问,从长远来看这会更昂贵).

The actual random number generator, on the other hand, is a heavy-weight object carrying a lot of state and requiring quite some time to be constructed, so that should only be initialised once per thread (or even across threads, but then you’d need to synchronise access which is more costly in the long run).

这篇关于如何生成线程安全的统一随机数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆