27

関数をタイムアウトする方法はありますか?私は仕事をするために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の次の要素に進む方法はありますか?

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

4

7 に答える 7

21

それはあなたの実装に依存します。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
  }
}

処理を中断できない別の例:

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);
}
于 2012-05-14T16:27:49.207 に答える
13

必要なのは、タイムアウト時に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

于 2015-05-27T02:46:43.457 に答える
9

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

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

于 2012-05-14T16:28:16.260 に答える
5

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

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

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

CURLオプションとCURL自体の詳細については、PHPのドキュメントも参照してください。

ただし、インストールされているlibcurlやcurlforphpがSSH/SFTPをサポートしていることを確認する必要があります。

お役に立てば幸いです...

于 2012-05-14T19:58:33.210 に答える
4

ループを開始する前に、を記憶する変数を設定します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.
}
?>
于 2012-05-14T16:29:00.803 に答える
1

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

于 2012-05-14T16:43:42.240 に答える
0

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

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";
于 2018-12-28T23:28:05.813 に答える