web-dev-qa-db-ja.com

PHPで関数をタイムアウトする

関数をタイムアウトさせる方法はありますか?仕事をするのに10分あります。ジョブにはforループが含まれています。以下に例を示します。

<?php
foreach($arr as $key => $value){
   some_function($key, $value); //This function does SSH and SFTP stuff
}
?>

$ arrには15個の要素があり、some_function()には1分以上かかる場合があります。実際、5分間絞首刑になりました。

関数呼び出しをタイムアウトし、$ arrの次の要素に進む方法はありますか?

ありがとうございました!!

21
Mo3z

実装に依存します。 PHPの関数の99%はブロックしています。現在の関数が完了するまで意味処理は続行されません。ただし、関数にループが含まれる場合は、独自のコードに追加してループを中断できます。特定の条件が満たされた後。

このようなもの:

foreach ($array as $value) {
  perform_task($value);
}

function perform_task($value) {
  $start_time = time();

  while(true) {
    if ((time() - $start_time) > 300) {
      return false; // timeout, function took longer than 300 seconds
    }
    // Other processing
  }
}

処理を中断する別の例IS NOT NOT:

foreach ($array as $value) {
  perform_task($value);
}

function perform_task($value) {
    // preg_replace is a blocking function
    // There's no way to break out of it after a certain amount of time.
    return preg_replace('/pattern/', 'replace', $value);
}
18
Mike B

PHPはシングルスレッドです... OSの機能を使用して別のプロセスをフォークする必要があります。

これを行う方法を知っている唯一の方法は、execコマンドを使用して別の完全なプロセスを分岐させることです。必要なものを別のスクリプトに入れ、そのスクリプトでexecを呼び出し、すぐに10分間スリープします。 10分経過してもプロセスが実行されている場合は、強制終了します。 (コマンドでバックグラウンドで新しいphpコードを実行し、コマンドラインで取得してexecコマンドから返すことにより、PIDを取得する必要があります)。

9
Ray

必要なのは、タイムアウト時にSIGALRMシグナルをトリガーするpcntl_alarm関数を使用することです。

例えば:

// 10 minutes
pcntl_alarm( 600 );
pcntl_signal(SIGALRM, function() { print( "Timed-out!\n" ); exit( 0 ); });

こちらをご覧くださいPHPマニュアルの詳細については http://php.net/manual/en/function.pcntl-alarm.php

8
Jacques

「curl」を使用してこれを実装してみてください。 Curlは--PHP-主にHTTP/FTPの処理に使用されますが、ssh/sftpを含む、より多くのプロトコルをサポートします。 、したがって、私は追加のアドバイスを与えることはできませんが、あなたはここでstackoverflowまたは他の場所で追加情報を見つけることができるはずです。

リクエストのタイムアウトを設定するために使用できるオプション「CURLOPT_TIMEOUT」があります(オプション「CURLOPT_CONNECTTIMEOUT」もあります)。タイムアウトをミリ秒単位の解像度(CURLOPT_TIMEOUT_MS/CURLOPT_CONNECTTIMEOUT_MS)で指定することもできます。

とにかく、cronjobの場合は、スクリプトの開始時と削除時、実行の終了時にスクリプトが書き込む追加の「ロックファイル」を使用することをお勧めします。スクリプト内でこのロックファイルを確認できるため、cronが最後の実行が終了する前にスクリプトをトリガーした場合、それ以上スクリプトを終了することができますやっています。これにより、スクリプトが並行して複数回実行されることがなくなります。

PHPドキュメンテーションでも、CURLオプションとCURL自体について詳しく知ることができます。

ただし、インストールされているphp用のlibcurlおよび/またはcurlがSSH/SFTPをサポートしていることを確認する必要があります。

等.

それが役立つことを願っています...

5
aurora

ループを開始する前に、time()を記憶する変数を設定します。各反復の終わりに、現在のtime()が60秒より大きいかどうかを確認します。その場合、break。例えば:

<?php
$startTime=time();
foreach($arr as $key => $value){
    some_function($key, $value); //This function does SSH and SFTP stuff
    if (time()-$startTime>60) break; //change 60 to the max time, in seconds.
}
?>
4
D. Strout

set_time_limit を見てください。実行時間のみを考慮しているため、関数自体は実際には望んでいません。つまり、実際の5秒は0.2秒しか実行されない可能性があります。しかし、リンクを見る理由はコメントのためです。ユーザーが投稿したいくつかのソリューションがあります。

1
Recognizer

コマンドラインを使用している場合は、スリープがどのように中断されるかを確認してください。

echo date("H:i:s\n");
pcntl_signal(SIGALRM ,function($signal){
echo "arghhh! i got interrupted \n";
},true);

pcntl_alarm(3);
sleep(20);
pcntl_signal_dispatch();


echo date("H:i:s\n");

pcntl_alarm(3);
sleep(20);

echo date("H:i:s\n");

pcntl_signal_dispatch();
echo "end\n";
0
user1418446