Multithreading 线程。数组中的最大值
实际上,比方说,两个线程开始了。和一个由5个元素组成的数组,所有的计算都是1次交易。2因缺乏工作而出现和死亡。或者,如果指定9999个元素,则他会在最后30-50个项目中醒来。在我看来,他并不是真正的多线程Multithreading 线程。数组中的最大值,multithreading,perl,Multithreading,Perl,实际上,比方说,两个线程开始了。和一个由5个元素组成的数组,所有的计算都是1次交易。2因缺乏工作而出现和死亡。或者,如果指定9999个元素,则他会在最后30-50个项目中醒来。在我看来,他并不是真正的多线程 #! usr/bin/perl -w use strict; use warnings; use 5.010; use threads; use threads::shared; use Data::Dumper; my $n=0; my $max:shared=0; my @thr
#! usr/bin/perl -w
use strict;
use warnings;
use 5.010;
use threads;
use threads::shared;
use Data::Dumper;
my $n=0;
my $max:shared=0;
my @threads;
my $shr:shared=0;
say "Enter the number of threads";
my $threads=<stdin>;
my @pack;
#Заполняем массив
say "Enter the number of array elements";
my $c=<stdin>;
for (my $i=0;$i<$c;$i++){
my $r= int rand 999;
@pack=(@pack,$r);
}
say @pack;
# Создаём нужное количество потоков
for my $t (1..$threads) {
push @threads,threads->create(\&find,$t);
}
# Дожидаемся окончания работы всех потоков
for my $t (@threads){ $t->join();}
sub find {
# Номер текущего потока
my $num= shift;
say "+Thread $num started";
while($n<=$#pack){
# Распределяем элементы по потокам
lock($shr);#lock ($max);
my $stg=1+$shr++;
# Если элементы закончились, прерываем работу
if ($stg>=$#pack+2) {
say "-Thread $num done. \n";
return;}
if($max<$pack[$n]){$max=$pack[$n];}
say "Thread: $num \tStage: $stg \tMax: $max";
$n++;
sleep 1+int rand (3);
}
}
#!usr/bin/perl-w
严格使用;
使用警告;
使用5.010;
使用线程;
使用线程::共享;
使用数据::转储程序;
我的$n=0;
我的$max:shared=0;
我的@threads;
我的$shr:shared=0;
说“输入线程数”;
我的$threads=;
我的@pack;
#Заполняем массив
说“输入数组元素的数量”;
我的$c=;
对于(my$i=0;$icreate(\&find,$t);
}
# Дожидаемся окончания работы всех потоков
对于我的$t(@threads){$t->join();}
子查找{
# Номер текущего потока
我的$num=shift;
说“+线程$num已启动”;
而($n=$#pack+2){
说“-Thread$num done.\n”;
返回;}
如果($max线程的整个工作代码位于一个块中,在该块中获得了锁($shr)
,则会阻止多个线程执行任何工作
听起来您有一个大数组,并且您希望工作线程处理该大数组的一部分
线程唯一需要同步的时间是抓取工作和更新结果时
请注意,在访问数组时需要将其锁定,但在工作时不能将其锁定,因此需要将“到工作单元”复制到线程局部变量中
follow查找数组中所有元素的总和
#!/usr/bin/perl
use strict;
use warnings;
use feature qw( say );
use threads;
use threads::shared;
use List::Util qw( sum );
# This is where the real work is done.
# Notice how it there's no thread-related code in it
# and how it doesn't use any shared variables.
sub work {
sleep(1+rand(3));
return sum(@_);
}
{
@ARGV == 3
or die("usage\n");
my ($data_size, $num_threads, $chunk_size) = @ARGV;
my $next :shared = 0;
my @data :shared;
my $sum :shared;
for (1..$data_size) {
push @data, int(rand(9999));
}
say "Without threads: ", sum @data;
for my $t (1..$num_threads) {
async {
say sprintf("[%s]: Worker started.", threads->tid);
LOOP: while (1) {
# Grab work.
my @local_data;
{
lock $next;
last LOOP if $next >= @data;
my $new_next = $next + $chunk_size;
$new_next = @data if $new_next > @data;
say sprintf("[%s] Processing %s..%s", threads->tid, $next, $new_next-1);
@local_data = @data[$next .. $new_next-1];
$next = $new_next;
}
my $local_sum = work(@local_data);
# Update results.
{ lock $sum; $sum += $local_sum; }
}
say sprintf("[%s] done.", threads->tid)
};
}
$_->join for threads->list;
say "With threads: $sum";
}
输出:
$ ./a 125 3 20
Without threads: 577556
[1]: Worker started.
[1] Processing 0..19
[2]: Worker started.
[2] Processing 20..39
[3]: Worker started.
[3] Processing 40..59
[2] Processing 60..79
[1] Processing 80..99
[3] Processing 100..119
[1] Processing 120..124
[2] done.
[1] done.
[3] done.
With threads: 577556
您还可以使用将作业或工作项传递给线程:将@data
拆分为块,并将对其副本的引用推送到这样一个队列中。然后线程将这些引用出列,取消引用,汇总,并添加(部分)全局$sum
的结果。将工作项推送到队列后,必须插入与线程数量相同的“undef”,以便每个线程在其循环中获得一个“undef”,并停止处理
较新版本的Thread::Queue
有一个方法end()
。在您的情况下,可以从主线程调用它(而不是排队n
undes)但结果几乎是一样的:线程中的dequeue
调用将返回剩余的项,然后为每个线程返回undef
。我更喜欢将undef
排入队列,因为它更显式(并且不取决于threads::Queue
的实际版本)
代码将是:
#!/usr/bin/env perl
use strict;
use warnings;
use threads;
use threads::shared;
use Thread::Queue;
use List::Util;
my $sum : shared = 0;
my $jobs = Thread::Queue->new();
sub add_in_thread
{
printf( "[%s] started\n", threads->tid() );
while ( my $workitem = $jobs->dequeue() ) {
printf( "[%s] Processing %d items\n", threads->tid(), scalar @{$workitem} );
my $local_sum = List::Util::sum( @{$workitem} );
{ lock $sum; $sum += $local_sum; }
sleep( 1 + rand(3) );
}
printf( "[%s] done\n", threads->tid() );
}
sub main
{
my ( $data_size, $num_threads, $chunk_size ) = @ARGV;
my @data = map { int( rand(9999) ) } ( 1 .. $data_size );
print "Without threads: ", List::Util::sum(@data), "\n";
# split @data into chunks and put references
# of copies of them into the $jobs queue
while ( my @chunk = splice( @data, 0, $chunk_size ) ) {
$jobs->enqueue( [@chunk] );
}
# add 'undef' for each thread so it knows when to finish:
$jobs->enqueue( (undef) x $num_threads );
# start threads:
threads->create('add_in_thread') foreach ( 1 .. $num_threads );
# wait for them to finish: }
$_->join() for threads->list();
print "With threads: $sum\n";
return 0;
}
exit( main() );
/so17.pl 125 3 20的输出
Without threads: 623399
[1] started
[1] Processing 20 items
[2] started
[2] Processing 20 items
[3] started
[3] Processing 20 items
[1] Processing 20 items
[2] Processing 20 items
[3] Processing 20 items
[1] Processing 5 items
[2] done
[3] done
[1] done
With threads: 623399
您也可以提前启动线程。它们将在while
循环中阻塞(实际上是在dequeue()
调用中),直到队列中有东西。如果未定义
(或其他错误值)他们将停止处理并结束。否则他们将处理该队列中的项目。Thread::queue
将执行所有锁定和同步操作。您甚至可以设置第二个队列,让线程将其结果推入其中,并让主线程从该第二个结果队列中获取结果。您可能需要开立一个帐户在上,因为此站点仅用于英语问题。线程的整个工作代码位于一个块中,其中获得了lock($shr)
,阻止了多个线程执行任何工作。哦,天哪..谢谢!)->end
实际上更明确。它在名称中就这样说。它也不太容易出错,并且在更多情况下很有用。///此外,您正在创建线程并以错误的顺序填充队列。尽快启动这些线程,以便它们可以尽快开始工作。///最后,您复制的帖子的整个要点是工作人员应该做任何琐碎的事情,特别是因为这是OP遇到麻烦的原因。线程循环最好与工作例程分开。我保留数组,因为我认为他可能想在实际代码中更新数组,但实际上我自己在这里使用thread::Queue(使用了我在前面的评论中提到的修复)。@ikegami->end()
是在T::Q 3.01(又称Perl 5.18)中引入的。我使用T::Q的时间更长,并且用于将UNDEF排队。此外,我误解了->end()
,错误地认为它会使一个退出队列()
call立即返回所有剩余的项目。在重新阅读文档后,我完全同意首选->end()
。///将工作线程代码与线程代码分离意味着将我的列表::Util::sum(…);
行移动到一个单独的函数中(如工作()
).grated.///毕竟,我的文章的目的是展示T::Q的实际应用。它非常优雅!Thread::Queue可以从CPAN安装。不需要将Perl升级到5.18。