PTh*_*sCS 29 c++ random multithreading
我的程序需要在某个范围内生成许多随机整数(int min,int max).每次通话都有不同的范围.什么是好的(最好是线程安全的)方法呢?以下不是线程安全的(并使用rand(),人们似乎不鼓励):
int intRand(const int & min, const int & max)
{
return (rand() % (max+1-min)) + min;
}
Run Code Online (Sandbox Code Playgroud)
这要慢得多,但使用<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);
}
Run Code Online (Sandbox Code Playgroud)
像这样的东西就是我想要的(虽然changeParameters函数不存在):
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);
}
Run Code Online (Sandbox Code Playgroud)
另一个选择是uniform_int_distribution在第一个例子中使用mod然后使用mod.但是,我正在进行统计工作,所以我希望数字来自尽可能无偏差的分布(例如,如果使用的分布范围不是(max-min)的倍数,则分布将略微偏置).这是一个选择,但同样,我想避免它.
解决方案此解决方案来自@ konrad-rudolph @ mark-ransom和@mathk的答案.随机数发生器的播种是为了满足我的特殊需要.更常见的方法是使用时间(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;
/* 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);
}
Run Code Online (Sandbox Code Playgroud)
Kon*_*lph 33
你试过这个吗?
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);
}
Run Code Online (Sandbox Code Playgroud)
分布非常便宜(它们将由优化器完全内联,因此唯一剩余的开销是实际的随机数重新缩放).不要害怕像你需要的那样经常重新生成它们 - 事实上,重置它们在概念上并不便宜(这就是为什么不存在这种操作).
另一方面,实际的随机数生成器是一个承载很多状态的重量级对象,需要相当长的时间来构造,因此每个线程只应初始化一次(或者甚至跨越线程,但是你要' d需要同步访问,从长远来看这是更昂贵的).
制作 generator static,所以它只创建一次。这更有效,因为好的生成器通常具有较大的内部状态;更重要的是,这意味着您实际上获得的是它生成的伪随机序列,而不是单独序列的(随机性低得多)初始值。
每次创建一个新的发行版;这些通常是具有很少状态的轻量级对象,尤其是像uniform_int_distribution.
为了线程安全,选项是让 generatorthread_local为每个线程使用不同的种子,或者用互斥锁保护它。前者可能更快,尤其是在存在大量争用的情况下,但会消耗更多内存。
| 归档时间: |
|
| 查看次数: |
22120 次 |
| 最近记录: |