hli*_*itz 15 c++ performance multithreading
仅创建一个线程并加入它会使主线程的执行速度减慢50%.正如您在下面的示例中所看到的,线程不执行任何操作,但仍然会对性能产生重大影响.我认为它可能是一个功率/频率缩放相关的问题,所以我试图在创建线程后无法休眠.以下程序如果编译
g++ -std=c++11 -o out thread_test.cpp -pthread
Run Code Online (Sandbox Code Playgroud)
显示结果
Before thread() trial 0 time: 312024526 ignore -1593025974
Before thread() trial 1 time: 243018707 ignore -494037597
Before thread() trial 2 time: 242929293 ignore 177714863
Before thread() trial 3 time: 242935290 ignore 129069571
Before thread() trial 4 time: 243113945 ignore 840242475
Before thread() trial 5 time: 242824224 ignore -1635749271
Before thread() trial 6 time: 242809490 ignore -1256215542
Before thread() trial 7 time: 242910180 ignore -555222712
Before thread() trial 8 time: 235645414 ignore 537501443
Before thread() trial 9 time: 235746347 ignore 118363977
After thread() trial 0 time: 567509646 ignore 223146324
After thread() trial 1 time: 476450035 ignore -393907838
After thread() trial 2 time: 476377789 ignore -1678874628
After thread() trial 3 time: 476377012 ignore -1015350122
After thread() trial 4 time: 476185152 ignore 2034280344
After thread() trial 5 time: 476420949 ignore -1647334529
After thread() trial 6 time: 476354679 ignore 441573900
After thread() trial 7 time: 476120322 ignore -1576726357
After thread() trial 8 time: 476464850 ignore -895798632
After thread() trial 9 time: 475996533 ignore -997590921
Run Code Online (Sandbox Code Playgroud)
而所有试验应该是相同的速度.
编辑:使用rdtsc()进行时间测量,使用更长的持续时间,使用计算结果
thread_test.cpp:
#include <ctime>
#include <thread>
#include <iostream>
int dorands(){
int a =0;
for(int i=0; i<10000000; i++){
a +=rand();
}
return a;
}
inline uint64_t rdtsc(){
uint32_t lo, hi;
__asm__ __volatile__ (
"xorl %%eax, %%eax\n"
"cpuid\n"
"rdtscp\n"
: "=a" (lo), "=d" (hi)
:
: "%ebx", "%ecx" );
return (uint64_t)hi << 32 | lo;
}
int foo(){return 0;}
int main(){
uint64_t begin;
uint64_t end;
for(int i = 0; i< 10; i++){
begin= rdtsc();
volatile int e = dorands();
end = rdtsc();
std::cout << "Before thread() trial "<<i<<" time: " << end-begin << " ignore " << e << std::endl;;
}
std::thread t1(foo);
t1.join();
for(int i = 0; i< 10; i++){
begin= rdtsc();
volatile int e = dorands();
end = rdtsc();
std::cout << "After thread() trial "<<i<<" time: " << end-begin << " ignore " << e << std::endl;;
}
return 1;
}
Run Code Online (Sandbox Code Playgroud)
Lig*_*ica 18
std::rand()
是rand()
gl,在glibc下调用__random()
.__random()
调用__libc_lock_lock()
和__libc_lock_unlock()
,我认为如果我们深入研究该代码,我们会发现在创建一个线程之前,这些锁本质上是一个无操作.
Jer*_*fin 10
我认为你遇到了一个基本的问题:至少在一个典型的多任务操作系统上,有一个范围从大约(比如)几毫秒到一秒左右,在这个范围内很难得到有意义的定时测量.
对于极短的序列,您可以使用时钟计数器(例如,x86上的RDTSC),并运行几次.如果在运行期间发生任务切换,它会非常糟糕,因为运行时间比其余时间长很多倍.
这指出了真正的问题:一旦你到达一个序列(比如你的)需要足够长的时间,几乎可以肯定在运行时至少会发生一个任务切换,那么你会遇到一个问题:时间丢失任务切换可以显着关闭时间.特别是,如果任务切换在一次运行期间发生,而不是在另一次运行期间发生,则可以使第二次显着快于第一次.
最终,你得到的任务花费的时间足够长,所有这些任务都包含多个任务开关,因此由于任务开关的数量而产生的差异在噪声中几乎消失了.
注意:理论上,clock
应该只测量CPU时间,而不是测量时钟时间.实际上,完全分解所有任务切换时间几乎是不可能的.
您的测试演示(或可能演示)另一个相当基本的问题:您dorand()
计算某些东西,但不(例如)打印出结果.一个足够智能的编译器可以(很容易地)推断出它基本上没有效果,并且基本上完全将它排除在外.
即使您打印出结果dorand
,也没有播种随机数生成器,因此需要在每次运行时生成相同的结果.同样,一个足够智能的编译器可以解决这个问题,并在编译时计算出正确的结果,并打印出三个正确的结果.为了防止我们可以(作为一种可能性)在每次运行时以不同方式播种随机数 - 通常的方法是检索当前时间,并将其传递给srand
.
为了消除(或至少减少)这些问题,我们可以重写代码如下:
#include <ctime>
#include <thread>
#include <iostream>
long long int dorands(){
long long int a =0;
for(int i=0; i<100000000; i++){
a +=rand();
}
return a;
}
int foo(){return 0;}
int main(){
srand(time(NULL));
clock_t begin = clock();
long long int e = dorands();
clock_t end = clock();
std::cout << "ignore: " << e << ", trial 1 time: " << end-begin << std::endl;;
begin = clock();
e = dorands();
end = clock();
std::cout << "ignore: " << e << ", trial 2 time: " << end - begin << std::endl;;
std::thread t1(foo);
t1.join();
begin = clock();
e = dorands();
end = clock();
std::cout << "ignore: " << e << ", trial 3 time: " << end - begin << std::endl;;
begin = clock();
e = dorands();
end = clock();
std::cout << "ignore: " << e << ", trial 4 time: " << end - begin << std::endl;;
return 1;
}
Run Code Online (Sandbox Code Playgroud)
这里我打印出了返回的值dorand
,因此编译器不能只是完全跳过调用rand
.我也增加了里面的数字,dorand
所以每次试运行至少一秒钟(在我的电脑上,他们无论如何都会这样做).
运行它,我得到这样的结果:
ignore: 1638407535924, trial 1 time: 1519
ignore: 1638386748597, trial 2 time: 1455
ignore: 1638433228933, trial 3 time: 1433
ignore: 1638288863328, trial 4 time: 1491
Run Code Online (Sandbox Code Playgroud)
在这个特定的运行中,第一次试验比第二次试验慢(平均),但是有足够的变化和重叠,我们可能非常安全地猜测它只是噪音 - 如果平均速度有任何真正的差异,那就太多了太小,我们无法衡量.
归档时间: |
|
查看次数: |
1331 次 |
最近记录: |