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

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

问题描述

我的程序需要在一些范围内生成许多随机整数(int min,int max)。每个调用都会有一个不同的范围。什么是好的(最好是线程安全的)这样做?下面是不是线程安全的(和使用rand(),人们似乎劝阻):

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

很多较慢,但使用< random>

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

这是我要做的东西(changeParameters函数` t存在):

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

另一种选择是在 uniform_int_distribution ,然后在第一个示例中使用mod。但是,我正在做统计工作,所以我想让数字从尽可能无偏的分布(例如,如果使用的分布范围不是(max-min)的倍数,分布将稍微偏置)。

解决方案这个解决方案来自于@ konrad-rudolph @的解决方案, mark-ransom和@mathk。随机数发生器的播种是为了满足我的特定需要。更常见的方法是使用time(NULL)。如果你在同一秒钟做了很多线程,他们会得到相同的种子。即使有clock()这是一个问题,所以我们包括线程ID。缺点 - 这会泄漏内存 ---每个线程一个生成器。

  #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;

/ *线程安全函数,返回最小和最大(包括)之间的随机数。
这个函数需要〜142%的时间调用rand()。对于这额外的
成本,你得到一个更好的均匀分布和线程安全。 * /
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>分布(min,max);
return distribution(* generator);
}


解决方案

/ p>

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

分发极其便宜(它们将被优化器完全内联,只剩下的开销是实际的随机数重新调整)。不要害怕根据需要重新生成它们 - 事实上,重置它们在概念上并不便宜(这就是为什么该操作不存在)。



另一方面,实际的随机数生成器是一个重量级的对象,它承载着很多状态,并且需要相当多的时间来构造,所以只应该每个线程初始化一次(或者甚至跨线程,需要同步访问,这在长期内是更昂贵的)。


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;
}

This is much slower, but uses <random>:

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

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);
}

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.

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);
}

解决方案

Have you tried this?

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天全站免登陆