注:本文仅个人测试记录,不具备通用性,如有错误,欢迎指正。谢谢!
环境:Win7 x64,32G内存,8核,2.7GHz
开发环境:VS2015, Release
目标:C++ 多线程在内存、线程数量、耗时方面简单测试
代码:
#include <iostream>
#include <sstream>
#include <vector>
#include <array>
#include <thread>
#include <time.h>
#include <memory>
using namespace std;
const int numberCount = 1e10;
void Test()
{
std::vector<int> data(numberCount);
for (int i = 0; i < numberCount; ++i)
{
data[i] = 1;
}
}
void DoubleTest()
{
Test();
Test();
}
int main()
{
int count = 8;
int startTime = clock();
for (int i = 0; i < count; ++i)
{
Test();
}
int endTime = clock();
cout << "single time : " << (endTime - startTime) << endl;
std::thread threads[8];
for (int i = 0; i < count; ++i)
{
threads[i] = thread(Test);
}
for (int i = 0; i < count; ++i)
{
threads[i].join();
}
int endTime2 = clock();
cout << "mul time : " << (endTime2 - endTime) << endl;
system("pause");
}
测试结果:
插入一句:如果Test()函数中仅仅是int赋值,没有vector,测试结果单线程永远比多线程快,时间为多线程的1/2左右,原因不明!
使用单线程运行时:
内存: 13% ,25%, 20%,30%,24%...在一定范围内上下浮动
耗时: 16727 ms
使用多线程运行时,join()的位置不同结果也不同,如下图所示:
A: 如果分开separate:
内存: 18%,32%,49%,62%,90%,98%,然后停了1,2分钟,99%,电脑卡死,重启电脑
测试了两次,都是卡死,必须重启电脑,所以这种方式存在危险。
耗时: 卡死,XXXms
然后把代码改成4个线程,每个线程计算两个函数,就可以计算成功
内存: 17%,30%,44%,58%,72%,84%,80%,45%,22%,37%,49%,63%,78%,84%,64%,25%,17%结束
耗时: 第一次 14872 ms ,第二次 15327ms.....
B: 如果不分开 merge:
内存:变化上大致等于单线程
耗时:16488ms,略等于单线程
测试了多次,merge方式和单线程方式内存耗时几乎相等,可以认定两者相等。
首先确认一点,join必须分开,而且网上很多示例都是splite的,所以以splite方式作为目标继续深入。
上面是循环了8次进行的测试,然后for循环4次,测试3遍,结果如下:
测试三次,发现splite的时间要比单线程时间少一点。
然后for循环2次进行测试,测试3遍,结果如下:
测试结果:多线程仅比单线程耗时少1s左右,时间上并没有成倍关系,而且使用多线程还会存在系统崩溃的危险!
到现在需要思考以下问题:
1. 线程数量如何确定,每个线程所处理的数据量大小如何确定
2. 如何提升计算效率,时间上的成倍关系如何体现
分析:
第一个问题,线程数量如何确定?
百度搜到的结果是使用 std::thread::hardware_concurrency(),
通过这个函数得到了 8,然后查看计算机CPU核数也的确是8,但编程的结果很明显 8个线程是不对的!
个人推测:以32G为例,如果是8核,平均每个线程处理的数据量理想状态是4G,加上硬件本身计算是用1000而不是1024,
还要考虑系统其它进程占用资源,所以实际可用内存肯定不够4G,假设为3.5G
粗略换算:3.5G = 3 500M=3 500 000KB=3 500 000 000B
而我们的vector<int>data(1e10) 所占用的内存=sizeof(int) *data.size() = 4* 1e10= 40 000 000 000B
其实这里存在一个误区,就是int值的范围,如果给int变量赋值1e10, 它实际的值是1 410 065 408
重新计算vector<int>data(1e10) 所占用的内存=sizeof(int) *data.size() = 4* 1410065408= 5 640 261 632B
也就是说当我们开了8个线程时,需要的内存大于分配的内存,所以就会造成卡死的情况。
所以我们在设置线程数量时,首先要评估计算量所需内存。
个人建议:如果你的内存是32G,那么你的程序分配的内存应该在16G上,因为32G全部分配是不可能的,
而且越到后面的线程,调试结果看起来越慢。确定好分配的内存空间后,然后根据计算量X,线程数=16/X
第二个问题,效率提升并没有成倍的缩减啊,这是为什么呢?