2012-05-14 17 views
17

¿Hay alguna manera de desconectar una función? Tengo 10 minutos para realizar un trabajo. El trabajo incluye un bucle, aquí está un ejemplo:Tiempo de espera una función en PHP

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

$ matriz tiene 15 elementos y some_function() a veces puede tardar más de 1 minuto. De hecho, una vez que fue ahorcado por 5 minutos.

¿Hay alguna forma de que pueda superar el tiempo de espera de la llamada de función y continuar con el siguiente elemento en $ arr?

Gracias!

+0

algunas preguntas: ¿Qué pasa, que se limita a 10 minutos? no importa, si los trabajos ssh/sftp se ejecutan o no? y puede solucionar esta limitación mediante el uso de algún tipo de cola? – aurora

+0

Es un script crontab que se ejecuta cada 10 minutos. Está comprobando el estado de los servidores y actualizando la base de datos. Si no recibo respuesta en 1 minuto, estoy configurando ese servidor servidor lento ... – Mo3z

Respuesta

13

Depende de su implementación. El 99% de las funciones en PHP son bloqueantes. El procesamiento del significado no continuará hasta que la función actual se haya completado. Sin embargo, si la función contiene un bucle, puede agregar su propio código para interrumpir el bucle después de que se haya cumplido una determinada condición.

Algo como esto:

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

Otro ejemplo en el que interrumpir el procesamiento no es posible:

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); 
} 
+0

Gracias Mike, pero yo soy some_function o perform_task es una función central y estoy tratando de evitar la modificación del método central. – Mo3z

+1

Yendo por la ruta: creando un nuevo script example.php y llamando ese script en some_function y definiendo set_time_limit ... la lógica de some_function se ejecutará en example.php .. – Mo3z

+0

mismo problema aquí, misma técnica. –

8

PHP es el único subproceso ... usted tiene que utilizar la capacidad de su sistema operativo a otro proceso tenedor .

La única forma en que sé cómo hacerlo es con el comando exec para desechar otro proceso completo. Ponga el material que desea sincronizado en un guión por separado, llame a Exec en el guión, y luego duerma inmediatamente durante 10 minutos. Si a los 10 minutos el proceso continúa ejecutándose, mátalo. (Debería tener su PID haciendo que el comando ejecute el nuevo código php en el fondo, obteniéndolo a través de la línea de comando y devolviéndolo desde el comando exec).

+0

No todos los PHP no son roscados –

4

Antes de comenzar en el ciclo, establezca una variable que recuerde el time(). Al final de cada iteración, verifique si el actual time() es más de 60 segundos mayor. Si es así, break. Por ejemplo:

<?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. 
} 
?> 
+0

Gracias David por su respuesta. No necesito romper el bucle for, necesito romper la función si lleva más de un minuto. – Mo3z

1

Eche un vistazo a set_time_limit. Ahora la función en sí misma no es realmente lo que desea, ya que solo toma en consideración el tiempo de ejecución, lo que significa que 5 segundos en la vida real aún podrían ser solo de 0.2 segundos de ejecución. Pero la razón para mirar el enlace es por los comentarios. Hay un par de soluciones que los usuarios han publicado.

5

Puede intentar implementar esto usando 'curl'. Curl es, desde PHP, utilizado principalmente para hacer cosas HTTP/FTP, pero admite muchos más protocolos, incluido ssh/sftp. Nunca he hecho algo relacionado con ssh/sftp usando curl, así que no puedo dar ningún consejo adicional, pero debería poder encontrar información adicional aquí en stackoverflow o en otro lugar.

Hay una opción "CURLOPT_TIMEOUT" que puede usar para configurar el tiempo de espera para su solicitud (también hay una opción "CURLOPT_CONNECTTIMEOUT"). Incluso puede especificar los tiempos de espera en una resolución de milisegundos (CURLOPT_TIMEOUT_MS/CURLOPT_CONNECTTIMEOUT_MS).

De todos modos: para un cronjob, le recomendaría utilizar un "archivo de bloqueo" adicional que su secuencia de comandos escribe cuando se inicia y quita cuando termina de ejecutarse. Puede verificar este archivo de bloqueo en su secuencia de comandos, de modo que si cron activa su secuencia de comandos antes de finalizada la última ejecución, puede simplemente salir de la secuencia de comandos sin realizar ninguna acción posterior. Eso asegura que su script no se ejecutará varias veces en paralelo.

Puede encontrar más información sobre las opciones de CURL y el rizo en sí en la documentación de PHP, también:

Usted tiene que asegurarse de que su libcurl instalado y/o curl para php admite SSH/SFTP, sin embargo:

etc.

Espero que ayude ...

7

Lo que se quiere es utilizar la función pcntl_alarm, lo que dará lugar a una señal de SIGALRM en tiempo de espera. Por ejemplo:

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

Por favor, vea aquí el manual de PHP para más información sobre esto: http://php.net/manual/en/function.pcntl-alarm.php

+2

Aquí hay una implementación completa: https://gist.github.com/avalanche123/3085581 –

Cuestiones relacionadas