- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我构建了一个顺序、多线程和多进程 (MPI) 版本的蒙特卡罗计算来比较并行编程技术。将顺序代码与 MPI 代码进行比较会产生预期的结果。对于非常大量的样本,MPI 代码运行速度大约快 5 倍,有 5 个进程执行计算。但是,我无法让多线程版本运行得更快,即使系统监视器显示多个内核正在处理计算。我在 Linux 上运行代码。除了多进程版本中的 MPI,我没有使用任何外部库。
在这种情况下,是什么导致多线程版本有效地花费相同的时间量,即使计算被均匀分布到已分配给不同内核的线程?我已经使所有可能的线程函数本地化,以希望消除错误共享,但与对所有内容使用全局变量相比,我没有看到任何变化。
顺序版本:
#include "common/common.hpp"
// Integral to evaluate
#define v(x) exp(x)
using namespace std;
int main(int argc, char **argv)
{
// Limits of integration
const double a = 0.0, b = 1.0;
// Read number of samples strata from command-line input
uint nSamples = atoi(argv[1]);
uint nStrata = atoi(argv[2]);
srand((int)time(0));
// Sums in each stratum
vector<uint> nSamples_s(nStrata, 0);
vector<double> sumX_s(nStrata, 0.0), sumX2_s(nStrata, 0.0);
double x, delta = (b-a)/nStrata;
uint s;
double mean, var;
for (uint i = 1; i <= nSamples; i++) {
// Sample random variable
x = a + (b-a)*((double)rand() / RAND_MAX);
// Select the matching stratum
s = nStrata*(x-a)/(b-a);
s = (s == nStrata) ? nStrata - 1 : s;
// Store sums
nSamples_s[s]++;
sumX_s[s] += delta*v(x);
sumX2_s[s] += pow(delta*v(x), 2.0);
}
// Calculate summary statistics
mean = 0.0;
var = 0.0;
for (uint j = 0; j < nStrata; j++) {
mean += sumX_s[j]/nSamples_s[j];
var += sumX2_s[j]/nSamples_s[j] - pow(sumX_s[j]/nSamples_s[j], 2.0);
}
// Output summary statistics
cout << "\nIntegral estimate: " << mean
<< "\n\tstddev = " << sqrt(var)
<< "\n\tstderr = " << sqrt(var/nSamples) << endl;
return 0;
}
多线程版本:
#include "common/common.hpp"
#include <thread>
#include <mutex>
using namespace std;
// Mutex for modifying summary statistics
mutex mtx;
// Integral to evaluate
#define v(x) exp(x)
double mean = 0.0, var = 0.0;
void partialSum(uint rank, uint numWorkers, double a, double b, uint nStrata, uint nSamples);
int main(int argc, char **argv)
{
// Limits of integration
const double a = 0.0, b = 1.0;
// Read number of samples and strata from command-line input
uint nSamples = atoi(argv[1]);
uint nStrata = atoi(argv[2]);
srand((int)time(0));
// Worker threads
const uint numWorkers = 5;
vector<thread> workers;
// Start threads
for (uint t = 0; t < numWorkers; t++)
workers.push_back(thread(partialSum, t, numWorkers, a, b, nStrata, nSamples));
// Wait for thread execution
for (uint t = 0; t < numWorkers; t++)
workers[t].join();
// Output summary statistics
cout << "\nIntegral estimate: " << mean
<< "\n\tstddev = " << sqrt(var)
<< "\n\tstderr = " << sqrt(var/nSamples) << endl;
return 0;
}
void partialSum(uint rank, uint numWorkers, double a, double b, uint nStrata, uint nSamples)
{
uint nStrata_t, nSamples_t; // Actual number of strata and samples handled by this thread
uint stdStrata_t; // Nominal number of strata per thread
nStrata_t = stdStrata_t = nStrata / numWorkers;
if (rank == numWorkers - 1)
nStrata_t += nStrata % numWorkers;
uint strataOffset = rank * stdStrata_t;
nSamples_t = stdStrata_t * (nSamples / nStrata);
if (rank == numWorkers - 1)
nSamples_t += nSamples % nStrata;
// Summed statistics for each stratum in this thread
vector<uint> nSamples_st(nStrata_t, 0);
vector<double> sumX_st(nStrata_t, 0.0), sumX2_st(nStrata_t, 0.0);
// Width of integration region for each stratum and for this thread
double delta_s = (b-a)/nStrata;
double delta_t = delta_s * nStrata_t;
double x; // Sampling variable
uint s; // Corresponding stratum
// Sum statistics
for (uint i = 0; i < nSamples_t; i++) {
// Sample random variable
x = delta_t*((double)rand() / RAND_MAX);
// Select the matching stratum
s = nStrata_t*x/delta_t;
s = (s == nStrata_t) ? nStrata_t - 1 : s;
// Store sums
nSamples_st[s]++;
sumX_st[s] += delta_s*v(x + a + strataOffset*delta_s);
sumX2_st[s] += pow(delta_s*v(x + a + strataOffset*delta_s), 2.0);
}
// Calculate summary statistics
double partialMean = 0.0, partialVar = 0.0;
for (uint j = 0; j < nStrata_t; j++) {
partialMean += sumX_st[j]/nSamples_st[j];
partialVar += sumX2_st[j]/nSamples_st[j] - pow(sumX_st[j]/nSamples_st[j], 2.0);
}
// Lock mutex until thread exit
lock_guard<mutex> lockStats(mtx);
// Add contributions from this thread to summary statistics
mean += partialMean;
var += partialVar;
}
MPI 版本:
#include "common/common.hpp"
#include <mpi.h>
// Limits of integration
const double a = 0.0, b = 1.0;
// Number of samples and strata
uint nSamples, nStrata;
// MPI process data
int numProcs, numWorkers, procRank;
// Integral to evaluate
#define v(x) exp(x)
#define MPI_TAG_MEAN 0
#define MPI_TAG_VAR 1
void partialSum();
void collectSums();
using namespace std;
int main(int argc, char **argv)
{
// MPI setup
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &numProcs);
MPI_Comm_rank(MPI_COMM_WORLD, &procRank);
// Number of slave processes
numWorkers = numProcs - 1;
assert(numWorkers > 0);
// Read number of samples and strata from command-line input
nSamples = atoi(argv[1]);
nStrata = atoi(argv[2]);
srand((int)time(0));
if (!procRank) { // Process 0
collectSums();
} else { // Worker processes
partialSum();
}
MPI_Finalize();
return 0;
}
void partialSum()
{
int stdStrata_p, stdSamples_p; // Nominal number of strata and samples per process
int nStrata_p, nSamples_p; // Actual number of strata and samples handled by this process
nStrata_p = stdStrata_p = nStrata / numWorkers;
if (procRank == numWorkers)
nStrata_p += nStrata % numWorkers;
int strataOffset = (procRank - 1) * stdStrata_p;
nSamples_p = stdSamples_p = nStrata_p * (nSamples / nStrata);
if (procRank == numWorkers)
nSamples_p += nSamples % nStrata;
// Sums in each stratum handled by this process
vector<uint> nSamples_sp(nStrata_p, 0);
vector<double> sumX_sp(nStrata_p, 0.0), sumX2_sp(nStrata_p, 0.0);
// Width of integration region for each stratum and this process
double delta_s = (b-a)/nStrata;
double delta_p = delta_s*nStrata_p;
double x; // Sampling variable
uint s; // Corresponding stratum
// Summed statistics
double mean, var;
for (int i = 0; i < nSamples_p; i++) {
// Sample random variable
x = delta_p*((double)rand() / RAND_MAX);
// Select the matching stratum
s = nStrata_p*x/delta_p;
s = (s == nStrata_p) ? nStrata_p - 1 : s;
// Store sums
nSamples_sp[s]++;
sumX_sp[s] += delta_s*v(x + a + strataOffset*delta_s);
sumX2_sp[s] += pow(delta_s*v(x + a + strataOffset*delta_s), 2.0);
}
mean = 0.0;
var = 0.0;
for (int j = 0; j < nStrata_p; j++) {
mean += sumX_sp[j]/nSamples_sp[j];
var += sumX2_sp[j]/nSamples_sp[j] - pow(sumX_sp[j]/nSamples_sp[j], 2.0);
}
MPI_Send(&mean, 1, MPI_DOUBLE, 0, MPI_TAG_MEAN, MPI_COMM_WORLD);
MPI_Send(&var, 1, MPI_DOUBLE, 0, MPI_TAG_VAR, MPI_COMM_WORLD);
}
void collectSums()
{
double mean = 0.0, var = 0.0;
for (int i = 0; i < 2*numWorkers; i++) {
double readBuf;
MPI_Status readStatus;
MPI_Recv(&readBuf, 1, MPI_DOUBLE, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &readStatus);
if (readStatus.MPI_TAG == MPI_TAG_MEAN)
mean += readBuf;
else if (readStatus.MPI_TAG == MPI_TAG_VAR)
var += readBuf;
}
// Output summary statistics
cout << "\nIntegral estimate: " << mean
<< "\n\tstddev = " << sqrt(var)
<< "\n\tstderr = " << sqrt(var/nSamples) << endl;
}
程序是这样编译和运行的:
$ g++ strat_samples.cpp -o strat_samples -std=gnu++11 -O2 -Wall
$ time ./strat_samples 100000000 100
Integral estimate: 1.71828
stddev = 0.000515958
stderr = 5.15958e-08
real 0m18.709s
user 0m18.704s
sys 0m0.000s
$ g++ strat_samples_thd.cpp -o strat_samples_thd -std=gnu++11 -lpthread -O2 -Wall
$ time ./strat_samples_thd 100000000 100
Integral estimate: 1.71828
stddev = 0.000515951
stderr = 5.15951e-08
real 0m18.981s
user 0m39.608s
sys 0m44.588s
$ mpic++ strat_samples_mpi.cpp -o strat_samples_mpi -std=gnu++11 -O2 -Wall
$ time mpirun -n 6 ./strat_samples_mpi 100000000 100
Integral estimate: 1.71828
stddev = 0.000515943
stderr = 5.15943e-08
real 0m7.601s
user 0m32.912s
sys 0m5.696s
注意:当您开始向命令行输入添加 0 时,MPI 版本的加速甚至更加显着。
最佳答案
每个伪随机数生成器 (PRNG) 都有一个状态。然而,在 rand
它隐藏的情况下,它在多线程代码中的使用会导致数据竞争,从而导致未定义的行为。此外,rand
也有其他明显的缺点。
如果您可以使用 C++11,请使用其random
库部分,每个线程使用一个 PRNG,使用适当的分布,并注意不要将相同值作为 PRNG 的种子。
关于c++ - 多线程蒙特卡洛计算没有加速,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48397313/
我想在我的 iPhone 应用程序中加入线性回归。经过一些搜索,我发现 Accelerate Framework 中的 LAPACK 和 BLAS 是正确的库。但是我很难将加速框架添加到我的 XCod
有什么方法可以加速 JS 脚本(我指的是一些复杂的 DOM 操作,比如游戏或动画)? 最佳答案 真的没有办法真正加快速度。您可以压缩它,但不会快很多。 关于Javascript 加速?,我们在Stac
有时,我必须为一个项目重新导入数据,从而将大约 360 万行读入 MySQL 表(目前是 InnoDB,但我实际上并不局限于这个引擎)。 “加载数据文件...”已被证明是最快的解决方案,但它有一个权衡
在尝试计算加速时,我被卡住了。所以给出的问题是: 问题 1 如果程序的 50% 增强了 2 倍,其余 50% 增强了 4 倍,那么由于增强而导致的整体加速是多少? Hints:考虑增强前(未增强)机器
目前我正在处理实时绘图,但可视化非常慢。我想知道你可以做些什么来加速 Matplotlib 中的事情: 后端如何影响性能?是否有后端 实时绘图比其他人更好吗? 我可以降低分辨率以提高 FPS 吗? 如
我有一个小型测试框架。它执行一个循环,执行以下操作: 生成一个小的 Haskell 源文件。 使用 runhaskell 执行此操作.该程序生成各种磁盘文件。 处理刚刚生成的磁盘文件。 这种情况发生了
这是我的网站:Instant-YouTube 如您所见,加载需要很长时间。在 IE8 及以下甚至有时会导致浏览器崩溃。我不确定是什么原因造成的。可能是 Clicksor 广告,但我认为是 swfobj
是否可以加速 SKSpriteNode? 我知道可以使用 node.physicsBody.velocity 轻松设置速度但是设置它的加速度有多难? 最佳答案 从牛顿第二定律倒推运动:F = m.a您
有没有人有加速 FCKEditor 的技术?是否有一些关键的 JavaScript 文件可以缩小或删除? 最佳答案 在最新版本 (3.0.1) 中,FCKEditor 已重命名为 CKEditor .
我有以下 MySQL 查询,需要一天多的时间才能执行: SELECT SN,NUMBER FROM a WHERE SN IN (SELECT LOWER_SN FROM b WHER
我现在正在开发一款使用加速来玩的游戏。我找到了如何让我的元素移动,但不改变它的“原点”,或者更准确地说,改变加速度计算的原点: 事实上,我的图像是移动的,它的中心是这样定义的: imageView.c
我有一个 mysql 表,其中存储有 4 列的成员消息: message_id(主键,自增) sender_id( key ) receiver_id( key ) 消息内容 我做了很多 SELECT
我在 cuda_computation.cu 中有以下代码 #include #include #include #include void checkCUDAError(const char
我正在使用 BeautifulSoup 在 for 循环中解析数千个网站。这是我的代码片段: def parse_decision(link): t1 = time.time() de
我正在使用 OpenCV 2.4 (C++) 在灰度图像上进行寻线。这涉及一些基本的图像处理步骤,如模糊、阈值、Canny 边缘检测器、梯度滤波器或霍夫变换。我必须在数千张图像上应用寻线算法。 考虑到
当我试图连续生成四次相同的报告时,我刚刚分析了我的报告应用程序。第一个用了 1859 毫秒,而后面的只用了 400 到 600 毫秒。对此的解释是什么?我能以某种方式使用它来使我的应用程序更快吗?报告
当我打开 Storyboard文件时,由于其中包含的 VC 数量,打开它需要 1-2 分钟。加快速度的最佳做法是什么?我们应该将一些 VC 移动到不同的 Storyboard文件中吗?我们是否应该使用
我有一个包含多个页面的 UIPageViewController。每个页面都是相同的 View Controller ,但会跟踪页码并显示 PDF 的正确页面。问题是每个 PDF 页面都需要在 cur
这实际上是两个问题,但它们非常相似,为了简单起见,我想将它们放在一起: 首先:给定一个已建立的 Java 项目,除了简单的代码内优化之外,还有哪些不错的方法可以加快它的速度? 其次:在用Java从头写
我有一个包含 1000 个条目的文档,其格式类似于:
我是一名优秀的程序员,十分优秀!