2010-03-16 33 views
8

Tôi có một tập lệnh Perl khởi chạy 2 luồng, một luồng cho mỗi bộ xử lý. Tôi cần nó để chờ đợi một sợi để kết thúc, nếu một sợi kết thúc một cái mới được sinh ra. Dường như phương thức kết nối chặn phần còn lại của chương trình, do đó luồng thứ hai không thể kết thúc cho đến khi tất cả mọi thứ mà luồng đầu tiên thực hiện được thực hiện để loại bỏ mục đích của nó.Trong Perl, làm thế nào tôi có thể chờ cho các chủ đề kết thúc song song?

Tôi đã thử phương pháp is_joinable nhưng điều đó dường như không làm điều đó.

Dưới đây là một số mã của tôi:

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"; 
} 

Kết quả của việc này là:

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 

Trả lời

5

Tôi nghĩ rằng bạn cần phải di chuyển mã mà kéo file tiếp theo trong danh sách vào chủ đề chính họ.

Vì vậy, mọi chuỗi sẽ không chỉ xử lý một tệp, nhưng tiếp tục xử lý cho đến khi danh sách trống.

Bằng cách này, bạn cũng tiết kiệm chi phí cho việc tạo chủ đề mới mọi lúc.

Chuỗi chính của bạn sau đó sẽ tham gia cả hai.

Tất nhiên, điều này yêu cầu đồng bộ hóa trong danh sách (để chúng không kéo cùng một dữ liệu). Cách khác, bạn có thể chia danh sách thành hai (một cho mỗi luồng), nhưng điều đó có thể dẫn đến phân phối không may mắn.

(PS: Không có Chúa Perl, chỉ là một nhà sư khiêm tốn)

+0

Hôm nay bạn là thần của tôi;) giải pháp tốt đẹp .. Một điều nữa: Để đặt các khóa trên danh sách, tôi thực hiện việc này: nếu (1 == 1) {lock (@file_list); $ file = shift (@file_list); } Tôi cần điều này nếu nó được mở khóa ở cuối trước khi chạy chức năng. Điều này có vẻ giống như một khá noob-hack mặc dù :) bất kỳ cách nào tốt hơn? – Pmarcoen

9

Trước hết, một vài nhận xét về chính mã. Bạn cần phải chắc chắn rằng bạn có:

use strict; 
use warnings; 

vào đầu mỗi kịch bản. Thứ hai:

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

là không cần thiết vì mảng trong ngữ cảnh vô hướng đánh giá số lượng phần tử trong mảng. Đó là:

$nofiles = @ARGV; 

một cách chính xác sẽ cung cấp cho bạn số lượng tập tin trong @ARGV không phụ thuộc vào giá trị của $[.

Cuối cùng, kịch bản có thể được thực hiện đơn giản hơn nhiều bằng cách phân vùng danh sách các tập tin trước khi bắt đầu chủ đề:

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'

Ngoài ra, bạn có thể cho các chủ đề chuyển sang công việc tiếp theo khi chúng được thực hiện:

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"; 
    } 
} 

Đầu ra:

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'
+0

cảm ơn bạn đã bình luận của bạn, đã thực hiện giải pháp của Thilo trước khi đọc ý kiến ​​của bạn để chọn câu trả lời của mình nhưng tôi chắc chắn sẽ sử dụng đề xuất của bạn! – Pmarcoen

+1

Mặc dù vậy, việc phân vùng bộ làm việc có thể dẫn đến sự phân phối không may mắn. – Thilo

Các vấn đề liên quan