所以我在使用线程支持编译的核心2 duo macbook pro上运行perl 5.10:usethreads=define
,useithreads=define
。我有一个简单的脚本来读取4个gzip文件,每个文件包含750000行。我正在使用Compress::Zlib来解压缩和读取文件。我有2个实现,它们之间的唯一区别是包含use threads
。除此之外,两个脚本都运行相同的子程序来进行读取。因此,在伪代码中,非线程程序执行此操作:
read_gzipped(file1);
read_gzipped(file2);
read_gzipped(file3);
read_gzipped(file4);
线程版本如下:
my thr0 = threads->new(\$read_gzipped,'file1')
my thr1 = threads->new(\$read_gzipped,'file1')
my thr2 = threads->new(\$read_gzipped,'file1')
my thr3 = threads->new(\$read_gzipped,'file1')
thr0->join()
thr1->join()
thr2->join()
thr3->join()
现在,线程版本的运行速度几乎比非线程脚本快2倍。这显然不是我希望的结果。谁能解释我在这里做错了什么?
答案 0 :(得分:10)
你正在使用线程来尝试加速IO绑定的东西,而不是CPU绑定的东西。这只会引入更多的IO争用,这会减慢脚本速度。
答案 1 :(得分:9)
我的猜测是GZIP操作的瓶颈是磁盘访问。如果您有四个线程在platter硬盘上竞争磁盘访问,那么这会大大减慢速度。磁盘头必须快速连续移动到不同的文件。如果您一次只处理一个文件,则磁头可以保持在该文件附近,并且磁盘缓存将更准确。
答案 2 :(得分:4)
使用Parallel::ForkManager模块可以轻松解决问题。
通常 - Perl中的线程并不是很好。
答案 3 :(得分:0)
我不准备假设您在运行时没有看到top
的输出而受到I / O限制。和depesz一样,我倾向于认为压缩/解压缩操作(数学上很重)更容易受CPU限制。
当您处理CPU绑定操作时,使用比处理器更多的线程/进程几乎永远不会 [1]改善问题 - 如果CPU利用率已经达到100%,更多线程/进程不会神奇地增加其容量 - 并且最有可能通过增加更多的上下文切换开销来使事情变得更糟。
[1]我听说它建议重建编译,例如构建新内核,可以告诉make
使用两倍于机器有处理器的进程,我的个人经验就是这个似乎是准确的。我听到的解释是,这允许每个CPU在一个进程中忙于编译,而另一个进程正在等待从主存储器中提取数据。如果将编译视为受CPU限制的进程,则这是普通规则的例外。如果您将其视为I / O绑定的情况(I / O位于CPU和主内存之间而不是磁盘/网络/用户I / O),则不是。