当内存使用变高时,Perl多线程会变慢



大家好~我用Perl写了一个非常简单的多线程代码。代码如下:

#!/bin/perl
use strict;
use threads;
use Benchmark qw(:hireswallclock);
my $starttime;
my $finishtime;
my $timespent;
my $num_of_threads = 1;
my $total_size = 10000000;
my $chunk_size = int($total_size / $num_of_threads);
if($total_size % $num_of_threads){
$chunk_size++;
}
my @threads = ();
$starttime = Benchmark->new;
for(my $i = 0; $i < $num_of_threads; $i++) {
my $thread = threads->new(&search);
push (@threads, $thread);
}
foreach my $thread (@threads) {
$thread->join();
}
my $finishtime = Benchmark->new;
$timespent = timediff($finishtime, $starttime);
print "$num_of_threads threads used in ".timestr($timespent)."nDone!n";
sub search{
my $i = 0;
while($i < $chunk_size){
$i++;
}
return 1;
}

这段代码工作得很好,因为当增加线程数时,它会运行得更快。

但是,当在中间添加额外的行时,这将创建一个大大小的数组,当添加更多线程时,代码将运行得更慢。带有附加行的代码如下所示。

#!/bin/perl
use strict;
use threads;
use Benchmark qw(:hireswallclock);
my $starttime;
my $finishtime;
my $timespent;
my $num_of_threads = 1;
my $total_size = 10000000;
my $chunk_size = int($total_size / $num_of_threads);
if($total_size % $num_of_threads){
$chunk_size++;
}
##########Additional codes##########
print "Preparing data...n";
$starttime = Benchmark->new;
my @array = ();
for(my $i = 0; $i < $total_size; $i++){
my $rn = rand();
push(@array, $rn);
}
$finishtime = Benchmark->new;
$timespent = timediff($finishtime, $starttime);
print "Used ".timestr($timespent)."n";
######################################
my @threads = ();
$starttime = Benchmark->new;
for(my $i = 0; $i < $num_of_threads; $i++) {
my $thread = threads->new(&search);
push (@threads, $thread);
}
foreach my $thread (@threads) {
$thread->join();
}
my $finishtime = Benchmark->new;
$timespent = timediff($finishtime, $starttime);
print "$num_of_threads threads used in ".timestr($timespent)."nDone!n";
sub search{
my $i = 0;
while($i < $chunk_size){
$i++;
}
return 1;
}

我对Perl多线程中的这种行为感到非常困惑。有人知道这里会出什么问题吗?

谢谢!

您必须记住,当使用线程(解释器线程)时,整个Perl解释器,包括代码和内存,都被克隆到新线程中。所以要克隆的数据越多,需要的时间就越长。有很多方法可以控制被克隆的东西;查看threadsperldoc.

你应该尽可能少地加载模块,甚至在你生成了你的线程之后才加载很多模块。

如果您确实有很多数据将被所有线程使用,则将其与threads::shared共享。然后使用shared_clone()实现数据结构的共享。除了一个简单的变量之外,您不能简单地share()任何东西。该共享变量只能包含纯标量或其他共享引用。

如果您要使用或泵送该数据,请使用Thread::Queue模块将其设置为队列。它会自动共享这些值并负责锁定。在生成工作线程池之后,用Thread::Semaphore控制它们。这样他们就不会在你让他们有事可做之前就终止。您还可以防止竞态条件。

https://metacpan.org/pod/threads:共享

HTH

谢谢大家给我指路!我学习和尝试了不同的东西,包括如何使用共享和队列,应该可以解决这个问题。所以我将脚本修改如下:

#!/bin/perl
use strict;
use threads;
use threads::shared;
use Thread::Queue;
use Benchmark qw(:hireswallclock);
my $starttime;
my $finishtime;
my $timespent;
my $num_of_threads = shift @ARGV;
my $total_size = 100000;
######Initiation of a 2D queue######
print "Preparing queue...n";
$starttime = Benchmark->new;
my $queue = Thread::Queue->new();
for(my $i = 0; $i < $total_size; $i++){
my $rn1 = rand();
my $rn2 = rand();
my @interval :shared = sort($rn1, $rn2);
$queue->enqueue(@interval);
}
$finishtime = Benchmark->new;
$timespent = timediff($finishtime, $starttime);
print "Used ".timestr($timespent)."n";
#####################################
$starttime = Benchmark->new;
my $queue_copy = $queue; #Copy the 2D queue so that the original queue can be kept
for(my $i = 0; $i < $num_of_threads; $i++) {
my $thread = threads->create(&search, $queue_copy);
}
foreach my $thread (threads->list()) {
$thread->join();
}
$finishtime = Benchmark->new;
$timespent = timediff($finishtime, $starttime);
print "$num_of_threads threads used in ".timestr($timespent)."nDone!n";
#####################################
sub search{
my $temp_queue = $_[0];
while(my $temp_interval = $temp_queue->dequeue_nb()){
#Do something
}
return 1;
}

我要做的是,首先,创建一个数组队列,每个数组包含两个数字。我制作了一个队列的副本,因为我想在遍历时保留原始队列。然后使用多线程处理复制的队列。然而,我仍然发现当添加更多线程时,它运行得更慢,我不知道为什么。

最新更新