当内存使用率变高时 Perl 多线程变慢
Perl multithreading slower when memory usage getting high
大家好~我使用多线程在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 多线程中的这种行为感到很困惑。有谁知道这里可能出了什么问题吗?
谢谢!
您必须记住,当使用 ithreads(解释器线程)时,整个 Perl 解释器,包括代码和内存,都被克隆到新线程中。因此,要克隆的数据越多,所需的时间就越长。有一些方法可以控制克隆的内容;看看 threads
perldoc。
您应该尽可能少地执行操作,甚至在生成线程之前不要加载很多模块。
如果您确实有大量数据将被所有线程使用,请与 threads::shared
共享。然后共享一个数据结构使用shared_clone()
。你不能简单地 share()
任何东西,除了一个简单的变量。该共享变量只能包含普通标量或其他共享引用。
如果您要使用或抽取该数据,请使用 Thread::Queue
模块将其设为队列。它会自动共享值并负责锁定。生成工作线程池后,使用 Thread::Semaphore
控制它们。这样他们就不会在你给他们任何事情之前终止。您还可以防止竞争条件。
https://metacpan.org/pod/threads::shared
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;
}
我试图做的是,首先,制作一个数组队列,每个数组包含两个数字。制作了队列的副本,因为我想在通过它时保留原始队列。然后使用多线程完成复制的队列。但是,我仍然发现添加更多线程时它 运行 变慢,我不知道为什么。
大家好~我使用多线程在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 多线程中的这种行为感到很困惑。有谁知道这里可能出了什么问题吗?
谢谢!
您必须记住,当使用 ithreads(解释器线程)时,整个 Perl 解释器,包括代码和内存,都被克隆到新线程中。因此,要克隆的数据越多,所需的时间就越长。有一些方法可以控制克隆的内容;看看 threads
perldoc。
您应该尽可能少地执行操作,甚至在生成线程之前不要加载很多模块。
如果您确实有大量数据将被所有线程使用,请与 threads::shared
共享。然后共享一个数据结构使用shared_clone()
。你不能简单地 share()
任何东西,除了一个简单的变量。该共享变量只能包含普通标量或其他共享引用。
如果您要使用或抽取该数据,请使用 Thread::Queue
模块将其设为队列。它会自动共享值并负责锁定。生成工作线程池后,使用 Thread::Semaphore
控制它们。这样他们就不会在你给他们任何事情之前终止。您还可以防止竞争条件。
https://metacpan.org/pod/threads::shared
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;
}
我试图做的是,首先,制作一个数组队列,每个数组包含两个数字。制作了队列的副本,因为我想在通过它时保留原始队列。然后使用多线程完成复制的队列。但是,我仍然发现添加更多线程时它 运行 变慢,我不知道为什么。