【发布时间】:2014-02-23 22:21:50
【问题描述】:
我正在执行计算实验,这些实验需要可重现。因此,每个实验都使用自己的随机数生成器并记住它的种子:
class Experiment
{
public:
void operator()();
private:
unsigned seed_;
std::mt19937 engine_;
};
问题是引擎需要向下传递到最基本的功能。
假设调用堆栈的下 10 层有一个简单的函数,它需要一个引擎来生成一个介于 0 和 1 之间的随机数。然后需要将该引擎传递给这 10 个调用中的每一个,从而使代码成为乱七八糟的。
我考虑并拒绝了这两种方法:
1. global engine:
我会有一个全局引擎,所有的基本函数都会调用这个引擎。但是,如果我想在不同的线程中运行多个实验,这可能会导致问题。我在多线程方面的经验为零,但我得到了很多针对全局的建议,尤其是在多线程应用程序中,我不想朝着错误的方向迈出一步。
2. local engine in each small function.
每个函数都会在堆栈上创建一个引擎,使用它并在返回时销毁它。然而,这可能会导致性能问题,因为随机数生成器是一个大而复杂的对象。在我的实现中,它有 5000 个字节。
我应该使用什么方法?
【问题讨论】:
-
“然后,需要将该引擎传递给这 10 个调用中的每一个调用,从而使代码变得一团糟。” 你只需要传递 the 引擎,即
std::mt19937。您可以在本地创建 distributions,这可能很便宜,例如对于简单的分布,例如uniform_int_distribution。传递一个额外的参数到底有什么麻烦? -
可能是线程本地随机生成器。主要缺点:它是隐藏的可变状态。
-
@MartinDrozdik 您现在可以使用全局,以后可以机械地切换到使用线程局部。但是,仍然很难让它与并行性一起工作。您可能希望使用给定的种子启动每个并行工作程序。现在您必须将该种子推入该工人的线程本地。一切都是可行的,但隐含着很多魔法。我宁愿接受 Kerrek 的明确传递所有可变状态的想法。
-
@Martin 如果没有真正充分的理由,我真的不会使用本地线程。从可读性和维护的角度来看,它甚至比全局状态更糟糕(我编写的代码使用了很多 - 出于完全合理的原因 - 这并不有趣)。我对你为什么不能在课堂上共享引擎的解释仍然不完全满意。当然,您可能必须将该参数传递给标准 lib 函数一次,但这至多是单级间接。
-
@dyp 一些分发实现会缓存未使用的熵位,因此每次创建一个可能是浪费的。
标签: c++ multithreading c++11 random