В Perl, как я могу ожидать потоков для окончания параллельно?

У меня есть сценарий Perl, который запускает 2 потока, один для каждого процессора. Мне нужен он для ожидания потока для окончания, если один поток заканчивается порожден, новый. Кажется, что остальная часть блоков метода соединения программы, поэтому второй поток не может закончиться до всего, что первый поток делает сделан который вид поражений его цель.

Я попробовал is_joinable метод, но это, кажется, не делает это также.

Вот часть моего кода:

use threads;
use threads::shared;

@file_list = @ARGV;      #Our file list
$nofiles = $#file_list + 1; #Real number of files 
$currfile = 1;     #Current number of file to process

my %MSG : shared;              #shared hash

$thr0 = threads->new(\&process, shift(@file_list));
$currfile++;
$thr1 = threads->new(\&process, shift(@file_list));
$currfile++;

while(1){
 if ($thr0->is_joinable()) {
  $thr0->join;
        #check if there are files left to process
  if($currfile <= $nofiles){ 
   $thr0 = threads->new(\&process, shift(@file_list));
   $currfile++;
  }
 }

 if ($thr1->is_joinable()) {
  $thr1->join;
        #check if there are files left to process
  if($currfile <= $nofiles){
   $thr1 = threads->new(\&process, shift(@file_list));
   $currfile++;
  }
 }
}

sub process{
       print "Opening $currfile of $nofiles\n";
       #do some stuff
       if(some condition){
               lock(%MSG);
               #write stuff to hash
       }
       print "Closing $currfile of $nofiles\n";
}

Вывод этого:

Opening 1 of 4
Opening 2 of 4
Closing 1 of 4
Opening 3 of 4
Closing 3 of 4
Opening 4 of 4
Closing 2 of 4
Closing 4 of 4
8
задан niton 19 April 2015 в 15:17
поделиться

2 ответа

Я думаю, вам нужно переместить код, который извлекает следующий файл из списка, в сами потоки.

Таким образом, каждый поток будет не просто обрабатывать один файл, но продолжать обработку до тех пор, пока список не станет пустым.

Таким образом, вы также экономите на постоянном создании новых потоков.

Ваш основной поток затем присоединится к ним обоим.

Конечно, для этого требуется синхронизация списка (чтобы они не извлекали одни и те же данные). В качестве альтернативы вы можете разделить список на два (по одному для каждого потока), но это может привести к неудачному распределению.

(PS: Нет Perl God, просто скромный монах)

5
ответ дан 5 December 2019 в 12:09
поделиться

Прежде всего, несколько замечаний по самому коду. Вы должны убедиться, что у вас есть:

use strict;
use warnings;

в начале каждого скрипта. Во-вторых:

@file_list = @ARGV;      #Our file list
$nofiles = $#file_list + 1; #Real number of files 

не нужен, так как массив в скалярном контексте оценивается по количеству элементов в массиве. То есть:

$nofiles = @ARGV;

правильно выдаст вам количество файлов в @ARGV независимо от значения $[.

Наконец, сценарий можно значительно упростить, разбив список файлов на разделы перед запуском потоков:

use strict; use warnings;

use threads;
use threads::shared;

my @threads = (
    threads->new(\&process, @ARGV[0 .. @ARGV/2]),
    threads->new(\&process, @ARGV[@ARGV/2 + 1 .. @ARGV - 1]),
);

$_->join for @threads;

sub process {
    my @files = @_;
    warn "called with @files\n";
    for my $file ( @files ) {
        warn "opening '$file'\n";
        sleep rand 3;
        warn "closing '$file'\n";
    }
}

Output:

C:\Temp> thr 1 2 3 4 5
called with 1 2 3
opening '1'
called with 4 5
opening '4'
closing '4'
opening '5'
closing '1'
opening '2'
closing '5'
closing '2'
opening '3'
closing '3'

Или же можно позволить потокам переходить к следующей задаче по мере ее выполнения:

use strict; use warnings;

use threads;
use threads::shared;

my $current :shared;
$current = 0;

my @threads = map { threads->new(\&process, $_) } 1 .. 2;
$_->join for @threads;

sub process {
    my ($thr) = @_;
    warn "thread $thr stared\n";

    while ( 1 ) {
        my $file;
        {
            lock $current;
            return unless $current < @ARGV;
            $file = $ARGV[$current];
            ++ $current;
        }
        warn "$thr: opening '$file'\n";
        sleep rand 5;
        warn "$thr: closing '$file'\n";
    }
}

Output:

C:\Temp> thr 1 2 3 4 5
thread 1 stared
1: opening '1'
1: closing '1'
1: opening '2'
thread 2 stared
2: opening '3'
2: closing '3'
2: opening '4'
1: closing '2'
1: opening '5'
1: closing '5'
2: closing '4'
9
ответ дан 5 December 2019 в 12:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: