[Perl][threads]多線程循環處理任務
模塊
模塊選擇,最開始我用的是 Thread 模塊,用了一陣子感覺束手束腳,少了什麼。(在這之前我也沒接觸過線程)。然後重新去看 perldoc
You are strongly encouraged to migrate any existing threaded code to the new model (i.e., use the "threads" and "threads::shared" modules) as soon as possible.
所以 threads 和 threads::shared 才是更好的選擇。
情景模擬
假設現在進行一個網路下載任務,有一個網址列表,且單任務運行延遲比較高,需要等零點幾至一點幾秒。多線程的話,可能同樣是零點幾秒,多個網頁數據已經同時返回。
方案1
初始方案是,在主進程中,將網址列表保留到數組A,建立線程共享數組B,
每個線程對應數組B的一個元素,在線程中執行一個死循環,判斷如果元素是undef,則待命;否則執行特定任務,完成後該元素重新定義為 undef
在所有任務指派完成後,當數組B所有元素回歸到 undef,結束所有線程
=infon 523066680 2017-09n=cutnnuse threads;nuse threads::shared;nuse Time::HiRes qw/sleep time/;nuse IO::Handle;nSTDOUT->autoflush(1);nnour $idx = 0;nour @ths;nour @target :shared;nour @mission = qw/n baidu google souhu qiyi 163 bing vertex amazon n lofter foobar zhihu nvidia cuda perl metacpan rubyn pythonn/;nn#創建線程ngrep { push @ths, threads->create( &func, $_ ) } ( 0 .. 3 );nn#任務指派nwhile ( $#mission >= 0 )n{n for my $idx ( 0 .. $#ths )n {n if ( not defined $target[$idx] )n {n $target[$idx] = shift @mission;n }n }n}nn#等待線程任務完結nmy $wait = 1;nwhile ( $wait )n{n $wait = 0;n grep { $wait = 1 if ( defined $_ ) } @target;n}nn#線程終結和分離ngrep { $_->kill(BREAK)->detach() } threads->list(threads::all);nnsub funcn{n my $idx = shift;n my $time_a;nn $SIG{BREAK} = sub { threads->exit() };nn while (1)n {n if ( defined $target[$idx] )n {n $time_a = time();nn #假設時間消耗n sleep rand(2.0);nn #完成後任務信息輸出n printf "[%d] target: %-10s time used: %.2fn", n threads->tid(), $target[$idx], time() - $time_a;nn #清理任務記錄n $target[$idx] = undef;n }nn #待命n sleep 0.1;n }n}n
方案2
我拍一拍腦袋,好像繞了點,為什麼不直接共享所有地址數據,線程直接從數組中獲取?於是重寫了:
=infon 523066680 2017-09n=cutnnuse threads;nuse threads::shared;nuse Time::HiRes qw/sleep time/;nuse IO::Handle;nSTDOUT->autoflush(1);nnour $idx = 0;nour @ths;nour @mission :shared; #共享到線程nn@mission = qw/n baidu google souhu qiyi 163 bing vertex amazon n lofter foobar zhihu nvidia cuda perl metacpan rubyn pythonn/;nn#創建線程ngrep { push @ths, threads->create( &func, $_ ) } ( 0 .. 3 );nn#等待運行結束nwhile ( threads->list(threads::running) ) { sleep 0.2 };nn#線程分離/結束ngrep { $_->detach() } threads->list(threads::all);nnsub funcn{n our @mission;n my $idx = shift;n my $time_a;n my $target;nn $SIG{BREAK} = sub { threads->exit() };nn while ( $#mission >= 0 )n {n $time_a = time();n $target = shift @mission;nn #假設時間消耗n sleep rand(2.0);nn #完成後任務信息輸出n printf "[%d] target: %-10s time used: %.2fn", n threads->tid(), $target, time() - $time_a;n }n}n
輸出樣本:
[1] target: baidu time used: 0.75
[4] target: qiyi time used: 0.91[2] target: google time used: 1.13[4] target: bing time used: 0.35[3] target: souhu time used: 1.47[3] target: lofter time used: 0.37
[1] target: 163 time used: 1.67[4] target: amazon time used: 1.53[4] target: nvidia time used: 0.12[2] target: vertex time used: 1.91
[3] target: foobar time used: 1.40[3] target: metacpan time used: 0.66[4] target: cuda time used: 1.20[2] target: perl time used: 1.25[1] target: zhihu time used: 1.99[3] target: ruby time used: 0.87[4] target: python time used: 1.58[Finished in 5.9s]
如果不使用多線程,這些時間累計是 19.16 秒
知乎什麼時候能內置支持markdown?
推薦閱讀: