我试图在多个pthread上运行一个函数,以提高效率和运行时间。此函数执行大量矩阵计算和打印语句。但是,当我运行测试以便查看性能改进时,单线程代码运行得更快。
我的测试如下:
- 对于单线程:运行一个调用该函数的for循环1:1000。
- 对于多pthreaded:Spawn 100 pthreads,有一个1000项的队列和一个pthread_cond_wait,并让线程运行该函数,直到队列为空。
这是我的pthreads代码(单线程只是一个for循环):
# include <iostream>
# include <string>
# include <pthread.h>
# include <queue>
using namespace std;
# define NUM_THREADS 100
int main ( );
queue<int> testQueue;
void *playQueue(void* arg);
void matrix_exponential_test01 ( );
void matrix_exponential_test02 ( );
pthread_mutex_t queueLock;
pthread_cond_t queue_cv;
int main()
{
pthread_t threads[NUM_THREADS];
pthread_mutex_init(&queueLock, NULL);
pthread_cond_init (&queue_cv, NULL);
for( int i=0; i < NUM_THREADS; i++ )
{
pthread_create(&threads[i], NULL, playQueue, (void*)NULL);
}
pthread_mutex_lock (&queueLock);
for(int z=0; z<1000; z++)
{
testQueue.push(1);
pthread_cond_signal(&queue_cv);
}
pthread_mutex_unlock (&queueLock);
pthread_mutex_destroy(&queueLock);
pthread_cond_destroy(&queue_cv);
pthread_cancel(NULL);*/
return 0;
}
void* playQueue(void* arg)
{
bool accept;
while(true)
{
pthread_cond_wait(&queue_cv, &queueLock);
accept = false;
if(!testQueue.empty())
{
testQueue.pop();
accept = true;
}
pthread_mutex_unlock (&queueLock);
if(accept)
{
runtest();
}
}
pthread_exit(NULL);
}
我的直觉告诉我,多线程版本应该运行得更快,但它没有。有原因,还是我的代码有问题?我在Windows上使用C ++,并且必须下载一个库来使用pthreads。
答案 0 :(得分:5)
首先,您的代码的编写方式是任何时候只有一个线程可以运行(线程正在工作时,您的互斥锁被锁定)。因此,在最佳中,您可以期望您的代码与单线程版本一样快。
此外,所有线程每次都在读取和写入相同的内存。通过这种方式,您可以强制CPU内核同步其缓存,这意味着总线上的负载实际上更多,而不是由单个线程引起的。由于您没有做任何计算上昂贵的工作,因此内存带宽很可能是您的实际瓶颈,因此缓存同步增加的总线负载会降低您的程序速度。有关详细信息,请查看http://en.wikipedia.org/wiki/False_sharing。
答案 1 :(得分:4)
如果runtest()
受CPU约束 - 也就是说,没有做任何可能会阻塞i / o等的事情 - 那么开始100个线程并没有多大意义,除非你有100个cpus /核心! [编辑:我现在注意到runtest()
做了一些打印声明......文件i / o可能不会阻止......所以不会释放CPU。]
当前显示的代码在填充队列时保留互斥锁,因此在队列填满之前不会启动任何内容。当队列填充完成1000次信号时,如果有任何已经达到pthread_cond_wait()
,那么希望它们都已经启动 - 所以所有100个都将等待互斥锁。
如图所示,playQueue()
中的等待被打破。它应该是:
pthread_mutex_wait(&queueLock) ;
while (testQueue.empty)
pthread_cond_wait(&queue_cv, &queueLock) ;
if (testQueue.eof)
val = NULL ;
else
val = testQueue.pop ;
pthread_mutex_unlock(&queueLock) ;
但是,即使这一切都已整理好,也不能保证你会看到性能的提升,除非runtest()
做了大量的工作。 [编辑:我现在注意到它确实&#34;很多矩阵计算&#34;,听起来它可能是很多工作。]
启动工作线程并填充队列的一个小建议可能是重叠的,例如,通过启动一个工作人员来启动所有其他工作,或启动一个线程来填充队列。
如果不能更多地了解问题,如果工作可以在工作线程中静态划分 - 例如,给第一个线程项0..9,第二个线程项10..19,依此类推 - 所以每个工作人员都可以忽略所有其他人,减少同步操作的数量。
答案 2 :(得分:1)
除了其他好的答案外,您说runtest()
函数执行了I / O.
所以你很可能是I / O绑定的,在这种情况下你的所有线程都必须像其他人一样排队等待清空他们的缓冲区。