Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 线程。数组中的最大值_Multithreading_Perl - Fatal编程技术网

Multithreading 线程。数组中的最大值

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

实际上,比方说,两个线程开始了。和一个由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 @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。