我正在进行多线程蒙特卡罗模拟,作为计算金融课程的一部分。通过执行多线程矩阵乘法示例,我已经实现了一个线程池类和并发队列类,我已经验证了它正在按预期工作。但是,我也在进行蒙特卡罗模拟,我已经实现了一个随机数生成器,它在数字生成中向前跳过(通过单线程和多线程计算产生相同的结果)。
monte carlo代码(不工作,4核心速度快4倍):
double mcProduct::mtPricer() {
vector<double> res;
res.resize(nPath);
threadPool pool; // Threadpool
vector<taskHandle> futs; // handles
ranGen ran; // Random number generator class
size_t firstPath = 0;
while (firstPath < nPath)
{
size_t lastPath = firstPath + pathsPrTask;
if (lastPath > nPath) lastPath = nPath;
futs.push_back(pool.submitTask(
[&, firstPath, lastPath]()
{
ranGen lran;
lran = ran; // Clone number generator using copy constructor
lran.skipAhead(firstPath);
for (size_t i = firstPath; i < lastPath; ++i)
{
const double st = applySDE(invNormalCdf(lran.nextU()));
res[i] = exp(-rate*mat)*mymax<double>(st - strike, 0.0);
}
return true;
}));
firstPath = lastPath;
}
// Wait for threads to complete
for_each(futs.begin(), futs.end(), mem_fn(&taskHandle::wait));
return vMean(res);
}
矩阵乘法代码(工作,大约快4倍)
double mcProduct::matrixMult() {
threadPool pool; // Threadpool
vector<taskHandle> futs; // handles
size_t firstPath = 0;
while (firstPath < nPath)
{
size_t lastPath = firstPath + pathsPrTask;
if (lastPath > nPath) lastPath = nPath;
futs.push_back(pool.submitTask(
[&, firstPath, lastPath]()
{
for (size_t i = firstPath; i < lastPath; ++i)
{
multAMatrix(); // Matrix multiplication void (30x30)
}
return true;
}));
firstPath = lastPath;
}
// Wait for threads to complete
for_each(futs.begin(), futs.end(), mem_fn(&taskHandle::wait));
return 0.0;
}
基本上,两个实现之间的区别在于我为每个任务分配复制了ranGen类实例(lambda中的submitTask可调用)。起初,我认为前面跳过可能会很慢,但事实并非如此。问题似乎在于这个“lran.nextU()”实现,它将随机数生成迭代1步(即产生一个新的随机数)。我一直在想这可能与错误共享或缓存未命中有关,但我有点想法。我的意图是不要在对象之间共享任何东西。我只想要一个随机数生成器的干净副本!
有什么想法吗?
提前致谢。