我创建了一个C ++函数,它是更大项目的一部分。这个功能被称为很多。为了提高性能,我们决定将该功能分为4个部分,每个部分并行运行。完整的程序只接受一个输入和一个输入,然后进行模拟,它将长度为2000的变量传递给相关函数。
此函数对变量进行操作(最多20,096次操作,150,000次加法,无乘法)。这些操作由func1和func2并行完成,两次(因此每次每个函数执行四分之一的操作时)。两个函数在内存中共享相同的输入(double Signal
大小为700(只读),double A, B, C, H
,(所有大小(双)5600,写入和读取))和输出(double L
大小700)。
不需要互斥锁,因为func1在A,B,C,H(读和写)的一半上工作,并在L中写入其一半,而func2在其一半中执行相同的操作。但是,有些函数或线程同时读取Signal。在第二次调用时,线程几乎执行相同的操作。
问题是Threaded程序的运行速度比串行程序慢一点。当我单独计算每个函数时,它们运行原始函数时间的总函数时间的1/4,这在func1被调用两次时是有意义的,并且func2也被调用两次。我使用clock_t clock()进行计时(这可以测量windows中的挂钟,而不是标准中指定的挂钟)。但这与Windows QueryPerformanceCounter等其他计时工具一致。
我把所有事情都计时,并尝试了我所看到的一切。我使用了优化的optoins -O3 O2 Ofast。我为每个线程创建了一个单独的内存(即使是只读数组,然后复制结果)。
我有两个理论 pthreads的1 - 开销正在花费与函数一样多的时间 2- main()在等待pthread_join时正在休眠。
我对理论2更有信心,因为他们只是把时间丢失在pthread_join的某个地方。
我写了这个示例代码来模拟问题。请注意,循环位置在我实现的算法中是必不可少的,因此使用较少循环的移动操作将不起作用。
注意,如果增加数据大小(j <10000和j <5000)并相应地减小计数范围,则线程程序的性能开始更好地执行。
这将在1.3秒内完成。
#include <math.h>
#include <pthread.h>
#include <iostream>
#include <time.h>
using namespace std;
int main(){
int i,m,j,k;
clock_t time_time;
time_time=clock();
for (int count =0 ; count<50000;++count){
for (j=0;j<10000;j++){
m=j;
k=j+1;
i=m*j;
}
}
cout<<"time spent = "<< double(clock()-time_time)/CLOCKS_PER_SEC<<endl;
}
在同一处理器上运行5秒钟。
#include <math.h>
#include <pthread.h>
#include <iostream>
#include <time.h>
using namespace std;
void test (int i);
void *thread_func(void *arg){
int idxThread = *((int *) arg);
test (1);
return NULL;
}
void test (int i){
int j,k,m;
int q=0,w=1,e=2,r=3,t=4;
int a=1,s=1,d=1,f=3,g=3;
for (j=0;j<5000;j++){
m=j;
k=j+1;
i=m*j;
}
}
int main(){
int numThreads=2;
clock_t time_time;
pthread_t threads[numThreads];
unsigned int threadIDs[numThreads];
time_time =clock();
for (int count =0 ; count<50000;++count){
for (unsigned int id = 0; id < numThreads; ++id)
{
threadIDs[id]=id;
pthread_create(&(threads[id]), NULL, thread_func, (void *) &(threadIDs[id]));
}
for (unsigned int id = 0; id < numThreads; ++id)
{
pthread_join(threads[id], NULL);
}
}
cout<<"time spent = "<< double(clock()-time_time)/CLOCKS_PER_SEC<<endl;
}
编辑:对线程函数的50000调用是为了说明问题,在我的代码中,它们只是对func1的两次调用,而func2是两次,这是4次创建和连接。这似乎需要2毫秒。
OS:windows,mingw32,pthreads C ++。 CPU i7,RAM:8Gb
makefile:
CC = g++ -O3 -I............ -Wformat -c
LINK = g++ -Wl,--stack,8388608 -o
LINKFLAGS = -lpthread
答案 0 :(得分:0)
在注释中说明@ melak47时,创建和加入线程所需的开销比线程本身中的每个代码执行花费的时间更长。
答案 1 :(得分:0)
不要创建和加入线程。保持一个线程池运行并根据需要为它们分配任务。
除非你别无选择,否则不要等待任务完成。相反,完成任务触发工作无需等待即可完成。