需要关于Linux上C语言中多线程分析的思考

Jun*_*aid 7 linux performance multithreading multicore pthreads

我的应用场景是这样的:我想评估一个可以在四核机器上实现的性能增益,以处理相同数量的数据.我有以下两种配置:

i)1-Process:没有任何线程的程序,处理来自1M .. 1G的数据,而系统假设只运行其4核的单核.

ii)4线程 - 进程:具有4个线程的程序(所有线程执行相同的操作)但处理25%的输入数据.

在我创建4线程的程序中,我使用了pthread的默认选项(即没有任何特定的pthread_attr_t).我认为,与1-Process配置相比,4线程配置的性能提升应该接近400%(或介于350%和400%之间).

我分析了创建线程所花费的时间,如下所示:

timer_start(&threadCreationTimer); 
pthread_create( &thread0, NULL, fun0, NULL );
pthread_create( &thread1, NULL, fun1, NULL );
pthread_create( &thread2, NULL, fun2, NULL );
pthread_create( &thread3, NULL, fun3, NULL );
threadCreationTime = timer_stop(&threadCreationTimer);

pthread_join(&thread0, NULL);
pthread_join(&thread1, NULL);
pthread_join(&thread2, NULL);
pthread_join(&thread3, NULL);    
Run Code Online (Sandbox Code Playgroud)

由于输入数据大小的增加也可能在每个线程的内存需求中增加,因此预先加载所有数据绝对不是一个可行的选择.因此,为了确保不增加每个线程的内存需求,每个线程以小块的形式读取数据,处理它并读取下一个块处理它等等.因此,由线程运行的函数代码的结构如下:

timer_start(&threadTimer[i]);
while(!dataFinished[i])
{
    threadTime[i] += timer_stop(&threadTimer[i]);
    data_source();
    timer_start(&threadTimer[i]);
    process();
}
threadTime[i] += timer_stop(&threadTimer[i]);
Run Code Online (Sandbox Code Playgroud)

变量在收到并处理所有需要的数据时由进程dataFinished[i]标记true.Process()知道什么时候这样做:-)

在main函数中,我正在计算4线程配置所需的时间,如下所示:

execTime4Thread = max(threadTime[0], threadTime[1], threadTime[2], threadTime[3]) + threadCreationTime.

并且简单地计算性能增益

gain = execTime1process / execTime4Thread * 100

问题: 在大约1M到4M的小数据大小上,性能增益通常很好(在350%到400%之间).然而,随着输入大小的增加,性能增益的趋势呈指数下降.它一直在减少,直到一些数据大小达到50M左右,然后变得稳定在200%左右.一旦达到这一点,即使1GB的数据也几乎保持稳定.

我的问题是,任何人都可以建议这种行为的主要原因(即,性能在开始时下降,但之后保持稳定)?

并建议如何解决这个问题?

为了您的信息,我也调查的行为threadCreationTimethreadTime每个线程,看看发生了什么.对于1M的数据,这些变量的值很小,但随着数据大小的增加,这两个变量都呈指数级增长(但threadCreationTime无论数据大小如何都应保持几乎相同,并且threadTime应以与正在处理的数据相对应的速率增加).继续增加直到50M左右threadCreationTime变得稳定并且threadTime(就像性能下降变得稳定)并且threadCreationTime以与待处理数据的增加相对应的恒定速率保持增加(这被认为是可理解的).

您是否认为增加每个线程的堆栈大小,处理优先级的东西或其他参数类型的调度程序(使用pthread_attr_init)的自定义值可以帮助?

PS:在Linux的故障安全模式下使用root运行程序时获得的结果(即,最小的操作系统在没有GUI和网络的情况下运行).

kfm*_*e04 2

由于输入数据大小的增加也可能会增加每个线程的内存需求,因此提前加载所有数据绝对不是一个可行的选择。因此,为了保证不增加每个线程的内存需求,每个线程以小块的形式读取数据,处理它并读取下一个块处理它,依此类推。

仅此一点,就足以导致速度急剧下降

如果有足够的内存,读取一大块输入数据总是比读取小块数据更快,尤其是从每个线程读取数据。当您将其分解为碎片时,任何来自分块(缓存效果)的 I/O 优势都会消失。即使分配一大块内存也比多次分配小块内存要便宜得多。

作为健全性检查,您可以运行htop以确保至少所有核心在运行期间都处于最高状态。如果不是,您的瓶颈可能位于多线程代码之外。

在螺纹内,

  • 由于许多线程而导致的线程上下文切换可能会导致加速效果不佳
  • 正如其他人提到的,由于不连续读取内存而导致的冷缓存可能会导致速度变慢

但是重新阅读你的OP,我怀疑速度减慢与你的数据输入/内存分配有关。您到底从哪里读取数据?某种插座?您确定需要在线程中多次分配内存吗?

工作线程中的某些算法可能不是最优的/昂贵的。