我创建了一个非常简单的应用来弄清楚boost :: thread是如何工作的。 我发现这个测试的结果令人惊讶。 4个执行线程完成计算比1个线程快2倍。 我期待4倍的提升。 另一个问题是为什么8个线程没有带来任何性能提升?
我正在使用boost 1.46.1和VS2008。完整的源代码如下。 程序在Core i5 750机器上运行。
#include <iostream>
#include <vector>
#include <cmath>
#include <boost/thread.hpp>
#include <boost/timer.hpp>
typedef unsigned int uint;
struct Vector {
float x, y, z;
Vector() : x(0.f), y(0.f), z(0.f) {}
float len() {
return sqrtf(x*x + y*y + z*z);
}
};
float norm(int a) {
return float((a % 10) + 1) / 10.f;
}
void genVectors(std::vector<Vector>& examples) {
srand(GetTickCount());
for (uint i = 0; i < examples.size(); ++i) {
examples[i].x = norm(rand());
examples[i].y = norm(rand());
examples[i].z = norm(rand());
}
}
typedef std::vector<Vector> Data;
typedef Data::iterator DataIter;
typedef std::vector<float> Result;
typedef Result::iterator ResultIter;
struct Worker {
Data data;
Result result;
Worker(DataIter& dataStart,
const DataIter& dataEnd,
ResultIter& resultStart,
const ResultIter& resultEnd) : data(dataStart, dataEnd), result(resultStart, resultEnd) {
assert(data.size() == result.size());
}
void operator()() {
DataIter di = data.begin();
ResultIter ri = result.begin();
const DataIter dend = data.end();
for (; di != dend; ++di, ++ri) {
*ri = di->len();
}
}
};
int main(int argc, char **argv) {
const uint numThreads = 4;
const uint seqLen = 13107200;
std::vector<Vector> a;
a.resize(seqLen);
genVectors(a);
std::vector<float> singleThreadResult(a.size());
assert(a.size() == singleThreadResult.size());
boost::timer singleThreadTimer;
for (uint i = 0; i < a.size(); ++i) {
singleThreadResult[i] = a[i].len();
}
double singleThreadTime = singleThreadTimer.elapsed();
std::vector<float> multiThreadResult(a.size());
Worker* workers[numThreads];
for (uint i = 0; i < numThreads; ++i) {
uint chunkSize = seqLen / numThreads;
assert(numThreads * chunkSize == seqLen);
workers[i] = new Worker(a.begin() + i*chunkSize,
a.begin() + (i+1)*chunkSize,
multiThreadResult.begin() + i*chunkSize,
multiThreadResult.begin() + (i+1)*chunkSize);
}
boost::timer multiThreadTimer;
boost::thread_group threads;
for (uint i = 0; i < numThreads; ++i) {
threads.create_thread(boost::ref(*workers[i]));
}
threads.join_all();
double multiThreadTime = multiThreadTimer.elapsed();
using namespace std;
cout << "Single thread time: " << singleThreadTime << endl;
cout << numThreads << " threads time: " << multiThreadTime << endl;
return 0;
}
答案 0 :(得分:2)
根据英特尔网站的说法,Core i5 750处理器有4个内核并支持4个线程,所以你不应该期望8个线程的性能比4个线程更多。通过为你的软件添加比你拥有的线程更多的线程处理器(或超线程)只是增加了更多的上下文切换开销。
至于为什么4个线程不快于2,我猜它是与工作数据集的大小有关。数据集比8MB缓存大得多,因此您的测试应用程序可能内存带宽有限。
要对此进行测试,请尝试使用适合缓存的数据集进行基准测试。
答案 1 :(得分:1)
您的Core i5 750计算机中可能有4个核心,但您仍然拥有单个数据总线。所有使用的数据(13107200 * 3 * sizeof(float)= 157 MB)必须通过此数据总线。然后有一个“仅仅”13107200 * sizeof(float)= 52 MB的结果向量,它采用相同的资源。所有这些都在缓存上很重,4个内核花费大量时间等待内存可用于读取或写入。
答案 2 :(得分:0)
我一直发现,对于在给定硬件配置上运行的给定问题,无法预测“最佳”线程数。我的方法是从命令行参数化线程数,并尝试各种数字,直到我达到“甜蜜点”。
答案 3 :(得分:0)
对于这样的场景,无论如何我更喜欢OpenMP #pragma parallel for
,或者只是使用gcc -fopenmp -D_GLIBCXX_PARALLEL
并且(可能)获得自动并行化......
答案 4 :(得分:0)
使用系统线程时,无法保证每个线程都在单独的核心上运行。您不能为线程分配核心 - 这是OS任务。鉴于您的应用程序中有4个线程,操作系统可以在单个核心上运行它们,具体取决于整体CPU负载和数十亿其他因素。