簡體   English   中英

Perl,Parallel :: ForkManager - 如何實現fork的超時

[英]Perl, Parallel::ForkManager - how to implement timeout for fork

是否可以使用Parallel :: ForkManager為fork實現某種超時(時間限制)?

Basic Parallel :: ForkManager腳本如下所示

use Parallel::ForkManager;
my $pm = Parallel::ForkManager->new( 10 );
for ( 1 .. 1000 ) {
    $pm->start and next;
    # some job for fork
    $pm->finish;
}
$pm->wait_all_children();

我想限制“#for work for fork”的時間。 例如,如果它沒有在90秒內完成。 那么它(fork)應該被殺死/終止。 我想過使用它,但我不得不說,我不知道如何在Parallel :: ForkManager中使用它。

編輯

感謝hobbs和ikegami。 你的建議都有效.....但只是在這個基本的例子中,而不是在我的實際腳本中:(。 截圖 這些叉子將永遠存在 - 說實話 - 我不知道為什么。 我使用這個腳本幾個月。 沒有改變任何東西(雖然許多事情取決於外部變量)。 每個fork都必須從網站下載頁面,解析它並將結果保存到文件中。 每叉不應超過30秒。 超時設置為180秒。 那些懸掛叉是完全隨機的,因此很難追蹤問題。 這就是為什么我想出一個臨時的,簡單的解決方案 - 超時和殺死。

什么可能在我的代碼中禁用(中斷)你的超時方法? 我的代碼中的任何地方都沒有任何其他alarm()

編輯2

其中一個分叉,懸掛1小時38分鍾並返回“超時PID” - 這就是我在die()鍵入的alarm() 所以超時工作...但它的晚期大約1小時36分鍾;)。 你有什么想法?

更新

很抱歉在收盤后更新,但如果我沒有指出Parallel :: ForkManager也支持run_on_start回調,那將是我的run_on_start 這可用於安裝“子注冊”功能,該功能負責為您提供PID的time()

例如,

$pm->run_on_start(sub { my $pid = shift; $workers{$pid} = time(); });

結果是,與下面描述的run_on_wait一起,P :: FM的主循環不需要做任何特殊的事情。 也就是說,它可以保持簡單的$pm->start and next ,並且回調將處理其他所有事情。

原始答案

Parallel :: ForkManager的run_on_wait處理程序和一些記賬,可以強制掛起和ALRM證明的孩子終止。

該函數注冊的回調可以定期運行,而$pm等待終止子進程。

use strict; use warnings;
use Parallel::ForkManager;

use constant PATIENCE => 90; # seconds

our %workers;

sub dismiss_hung_workers {
  while (my ($pid, $started_at) = each %workers) {
    next unless time() - $started_at > PATIENCE;
    kill TERM => $pid;
    delete $workers{$pid};
  }
}

...

sub main {
  my $pm = Parallel::ForkManager->new(10);
  $pm->run_on_wait(\&dismiss_hung_workers, 1);  # 1 second between callback invocations

  for (1 .. 1000) {
    if (my $pid = $pm->start) {
      $workers{$pid} = time();
      next;
    }
    # Here we are child.  Do some work.
    # (Maybe install a $SIG{TERM} handler for graceful shutdown!)
    ...
    $pm->finish;
  }

  $pm->wait_all_children;

}

(正如其他人所說,最好讓孩子通過alarm()來調節自己alarm() ,但這對你來說似乎是間歇性的。你也可以采取浪費,粗暴的行為,例如讓每個孩子自己fork() or exec('bash', '-c', 'sleep 90; kill -TERM $PPID') 。)

你只需要一行:

use Parallel::ForkManager;
my $pm = Parallel::ForkManager->new( 10 );
for ( 1 .. 1000 ) {
    $pm->start and next;
    alarm 90;             # <---
    # some job for fork
    $pm->finish;
}
$pm->wait_all_children();

您不需要設置信號處理程序,因為您的意思是讓進程死亡。

它即使你工作exec的孩子。 它不適用於Windows,但首先在Windows上使用fork是有問題的。

在你的子進程中(即在$pm->start and next以及循環結束之間)做你所鏈接的答案。你需要做什么才能讓它與Parallel :: ForkManager進行交互,其他而不是確保你不小心殺死父母:)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM