webentwicklung-frage-antwort-db.com.de

Timeout einer Funktion in PHP

Gibt es eine Möglichkeit, eine Funktion zu beenden? Ich habe 10 Minuten Zeit, um einen Job auszuführen. Der Job enthält eine for-Schleife, hier ein Beispiel:

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

$ arr hat 15 Elemente und some_function () kann manchmal mehr als 1 Minuten dauern. Einmal wurde es für 5 Minuten gehängt.

Gibt es eine Möglichkeit, die Funktion aufzurufen und mit dem nächsten Element in $ arr fortzufahren?

Vielen Dank!!

20
Mo3z

Das hängt von Ihrer Implementierung ab. 99% der Funktionen in PHP blockieren. Die Bedeutungsverarbeitung wird erst fortgesetzt, wenn die aktuelle Funktion abgeschlossen ist. Wenn die Funktion jedoch eine Schleife enthält, können Sie Ihren eigenen Code hinzufügen, um die Schleife zu unterbrechen, nachdem eine bestimmte Bedingung erfüllt wurde.

Etwas wie das:

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

Ein weiteres Beispiel, bei dem die Verarbeitung IS NICHT unterbrochen werden kann:

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);
}
17
Mike B

PHP ist Single-Threading ... Sie müssen die Fähigkeit Ihres Betriebssystems verwenden, um einen anderen Prozess zu aktivieren.

Die einzige Möglichkeit, wie ich dies tun kann, besteht darin, dass mit dem Befehl exec ein weiterer vollständiger Prozess ausgeführt wird. Legen Sie die Zeitvorgaben in einem separaten Skript ab, rufen Sie exec im Skript auf und schlafen Sie sofort für 10 Minuten. Wenn der Prozess nach 10 Minuten noch läuft, beenden Sie ihn. (Sie sollten die PID haben, indem Sie den neuen PHP-Code im Hintergrund ausführen lassen, ihn über die Befehlszeile abrufen und über den Befehl exec zurückgeben).

9
Ray

Sie möchten die pcntl_alarm-Funktion verwenden, die bei einem Timeout ein SIGALRM-Signal auslöst .. _. Beispiel:

// 10 minutes
pcntl_alarm( 600 );
pcntl_signal( 'SIGALRM', function() { print( "I am done!\n" ); exit( 0 ); } );

Weitere Informationen hierzu finden Sie im Handbuch PHP: http://php.net/manual/de/function.pcntl-alarm.php

7
Jacques

Sie könnten versuchen, dies mit 'curl' zu implementieren. Curl wird - von PHP - hauptsächlich für HTTP/FTP-Sachen verwendet, unterstützt jedoch viele weitere Protokolle, einschließlich ssh/sftp. Ich habe noch nie etwas gemacht, was ssh/sftp mit curl zu tun hatte, daher kann ich keine zusätzlichen Ratschläge geben, aber Sie sollten in der Lage sein, hier zusätzliche Informationen zu stackoverflow oder anderswo zu finden.

Es gibt eine Option "CURLOPT_TIMEOUT", mit der Sie das Zeitlimit für Ihre Anforderung konfigurieren können (es gibt auch eine Option "CURLOPT_CONNECTTIMEOUT"). Sie können die Timeouts sogar in Millisekundenauflösung angeben (CURLOPT_TIMEOUT_MS/CURLOPT_CONNECTTIMEOUT_MS). 

Wie auch immer: für einen Cronjob würde ich empfehlen, eine zusätzliche "Lock-Datei" zu verwenden, die Ihr Skript schreibt, wenn es gestartet und entfernt wird, wenn es fertig ausgeführt wird. Sie können nach dieser Sperrdatei in Ihrem Skript suchen. Wenn also cron Ihr Skript vorher auslöst, können Sie das Skript ohne weitere Schritte beenden. Dadurch wird sichergestellt, dass Ihr Skript nicht mehrmals parallel ausgeführt wird.

Weitere Informationen zu den CURL-Optionen und CURL selbst finden Sie auch in der Dokumentation PHP:

Sie müssen sicherstellen, dass Ihre installierte libcurl und/oder curl für php SSH/SFTP unterstützt.

usw.

Hoffentlich hilft das ...

5
aurora

Legen Sie vor Beginn der Schleife eine Variable fest, die die time() speichert. Prüfen Sie am Ende jeder Iteration, ob die aktuelle time() um mehr als 60 Sekunden größer ist. Wenn ja, break. Zum Beispiel:

<?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

Werfen Sie einen Blick auf set_time_limit . Jetzt ist die Funktion selbst nicht wirklich erwünscht, da sie nur die Ausführungszeit berücksichtigt, was bedeutet, dass 5 Sekunden im wirklichen Leben immer noch nur 0,2 Sekunden dauern können. Der Grund für das Betrachten des Links liegt jedoch in den Kommentaren. Es gibt ein paar Lösungen, die Benutzer gepostet haben. 

1
Recognizer

Für diejenigen von Ihnen, die sich in der Befehlszeile befinden, sehen Sie, wie der Schlaf unterbrochen wird:

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