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

时间:2011-12-08 19:59:15

标签: linux multithreading performance pthreads multicore

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

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

ii)4-threads-Process:具有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);    

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

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]);

变量dataFinished[i]在收到并处理所有需要的数据时按进程标记为trueProcess()知道何时这样做: - )

在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和网络的情况下运行)。

2 个答案:

答案 0 :(得分:2)

  

由于输入数据的大小增加也可能增加   每个线程的内存需求,然后提前加载所有数据   绝对不是一个可行的选择。因此,为了确保不   为了增加每个线程的内存需求,每个线程都会读取   小块数据,处理它并读取下一个块处理它和   等等。

就这一点而言,单独会导致速度急剧下降

如果有足够的内存,读取一大块输入数据总是比读取小块中的数据更快,特别是从每个线程中读取数据。当你将它分解成碎片时,任何来自分块(缓存效果)的I / O好处都会消失。即使分配一大块内存也比分配小块很多次便宜得多。

作为完整性检查,您可以运行htop以确保在运行期间至少所有核心都处于最佳状态。如果没有,您的瓶颈可能超出了多线程代码。

在线程中,

  • 线程上下文切换由于许多线程可能导致次优加速
  • 正如其他人所说,由于没有连续读取内存而导致冷缓存会导致速度减慢

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

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

答案 1 :(得分:0)

你的线程是否开始创作?如果是这种情况,则会发生以下情况:

当您的父线程正在创建线程时,已创建的线程将开始运行。当你点击timerStop(ThreadCreation计时器)时,这四个已经运行了 一段时间因此threadCreationTime重叠threadTime[i]

就像现在一样,你不知道自己在测量什么。这不会解决你的问题,因为很明显你有问题,因为threadTime没有线性增加,但至少你不会添加重叠时间。

要获得更多信息,您可以使用perf tool(如果您的发行版中有)。 例如:

perf stat -e cache-misses <your_prog>

看看双线程版本,三线程版本等会发生什么......