remove - ¿Puedes resolver este problema de sincronización de PHP?
strip_tags wordpress (6)
Experimentar:
Cambios significativos del código original:
1) Usar implicit_flush y todos los búferes se vacían antes de hacer cualquier cosa.
2) En lugar de generar solo un espacio, el código genera el número de iteración y 1023 bytes de otros datos para indicar al navegador que tenemos una buena cantidad de salida para mostrar. Un truco conocido normal.
3) Además de guardar el tiempo en el archivo de texto de salida, también guarda las iteraciones totales que ejecutó el código.
El código utilizado:
<?php
// Tricks to allow instant output
@ini_set(''implicit_flush'', 1);
for ($i = 0; $i < ob_get_level(); $i++)
ob_end_flush();
ob_implicit_flush(1);
//Your Code starts here
ignore_user_abort(true);
set_time_limit(0);
$begin_time = microtime(true);
$elapsed_time = 0;
while(!connection_aborted())
{
//this I changed, so that a looooong string is outputted
echo $i++.str_repeat('' '',1020).''<br/>'';
flush();
usleep(1000000);
}
$elapsed_time = microtime(true) - $begin_time;
$timer_seconds = $elapsed_time; //10 seconds
//Writes to file the number of ITERATIONS too along with time
$fp = fopen(''4765107.txt'', ''w'');
fwrite($fp, ''Time Elapsed: ''.$timer_seconds);
fwrite($fp, "/nIterations: ".$i);
fclose($fp);
?>
Demo en vivo:
Ahora, aquí está el código para ejecutar: http://work.sktnetwork.com/so/4765107.php
Y aquí está el archivo .TXT que genera: http://work.sktnetwork.com/so/4765107.txt
Lo que obtuve:
1) Cuando se ejecuta el código para 10 iteraciones y se hace clic en el botón STOP en el navegador, el archivo de salida muestra 13 iteraciones con ~ 13.01 segundos.
2) Cuando se ejecuta el código para 20 iteraciones y se hace clic en el botón PARAR en el navegador, el archivo de salida muestra 23 iteraciones con ~ 23.01 segundos.
Inferencias y Conclusión:
1) El script en realidad NO se detiene cuando se hace clic en el botón de DETENER, pero después de 2 a 4 segundos de hacer clic en él. Entonces, hay más iteraciones que las que aparecen en el navegador.
2) El número de iteraciones es MISMO que el número de segundos que se tarda en ejecutar, como se muestra en el archivo de salida.
Por lo tanto, no hay ningún error y aparentemente no hay errores, solo es el tiempo de latencia entre hacer clic en el botón DETENER y detener el script.
Notas:
1) Servidor: Un VPS de Linux.
2) Clientes probados: Firefox y Chrome.
3) Como la secuencia de comandos termina 2-4 segundos después de hacer clic en DETENER, el archivo de salida tarda alrededor de 3-4 segundos en actualizarse para la prueba actual.
¿Alguien puede decirme por qué cuando ejecuté un script con los contenidos a continuación y luego detuve después de 5 segundos que necesito dividir el tiempo transcurrido por 2 para obtener el tiempo de ejecución del script correcto?
ignore_user_abort(true); set_time_limit(0);
$begin_time = microtime(true);
$elapsed_time = 0;
while(!connection_aborted()) {
echo '' '';
flush();
usleep(1000000);
}
$elapsed_time = microtime(true) - $begin_time;
$timer_seconds = $elapsed_time; //10 seconds
$timer_seconds = $elapsed_time / 2; //5 seconds
/*I am writing to a DB - but you can use this to test */
$fp = fopen(''times.txt'', ''w'');
fwrite($fp, ''Time Elapsed: ''.$timer_seconds);
fclose($fp);
Siéntase libre de probar el código ya que me ha desconcertado sobre por qué el $elapsed_time
necesita dividirse entre dos. Tal vez he entendido mal algo?
Gracias a todos por cualquier ayuda
Actualizar
He actualizado el código para que cualquiera pueda probarlo y escriba en un archivo de texto para ver el resultado.
Confía en que connection_aborted()
es true
el momento en que presiona el botón "Detener" en su navegador, pero no ha demostrado que haya verificado que este es el caso. De hecho, no es.
Olvidaste cómo se produce la comprobación de "conexión abortada" en las redes. Una aplicación (php en este caso) no sabe qué pasó hasta que intenta escribir en la tubería.
El primer comentario sobre la documentación para connection_abort()
dice: "Para detectar una desconexión dentro del script, necesitamos vaciar el buffer (solo cuando el servidor intenta enviar el contenido del buffer que verá que la conexión es roto)."
Por lo tanto, no creo que puedas usar connection_abort()
de manera confiable.
Tenga la seguridad de que microtime()
funciona correctamente.
Esto no es tanto un "problema" como "por diseño"
Es una función de la forma en que funciona http.
Al enviar una página web a un cliente (navegador), el servidor ''DEBE'' enviar un encabezado de longitud de contenido. Ahora no puede saber la longitud del contenido hasta que lo tenga todo del script.
Por lo tanto, los servidores almacenan en búfer el resultado del script hasta que finalice el script.
Aquí es donde entran los caprichos. Dependiendo del servidor e incluso de las diferentes versiones del mismo servidor, puede o no verificar si el cliente se ha desconectado regularmente y, en caso afirmativo, esas comprobaciones pueden realizarse en diferentes intervalos de tiempo. que incluso puede cambiar dependiendo de qué tan ocupado esté el servidor.
PHP no tiene control sobre la conexión con el cliente, solo puede preguntar al servidor si la conexión aún existe. El servidor puede o no decir la verdad. Entonces la secuencia de comandos continúa ejecutándose (en el momento en que el servidor puede no saber).
Entonces, ¿por qué el trabajo de Mikushi después de agregar ob_end_flush () al inicio del script?
Bueno, eso es porque activó otra función de http llamada transferencia de fragmentos. Esto permite que los datos se envíen en fragmentos, cada uno con una versión especial del encabezado de longitud del contenido (en realidad no dice eso, solo envía la siguiente longitud del fragmento)
Prueba el guión de Mikushi con Wireshark y verás la codificación, aquí se muestra un ejemplo
HTTP/1.1 200 OK
Date: Tue, 01 Feb 2011 11:52:35 GMT
Server: Apache/2.2.3 (CentOS)
X-Powered-By: PHP/5.1.6
Connection: close
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8
7 <== this is the content-length
<pre>0
2 <== this is the content-length
1
2 ditto ...
2
2
3
2
4
2
5
Entonces esto significa que es imposible (sí, Tomalak me has entendido :)) saber cuándo el servidor va a terminar la conexión y, por lo tanto, devolver verdadero para connection_aborted () hasta que pruebes el servidor real involucrado. Porque cada uno es diferente Incluso el navegador web puede hacer algunas cosas que retrasa el cierre real, lo que puede enturbiar aún más el problema.
corriente continua
Usar su secuencia de comandos de fábrica no funciona correctamente en Ubuntu, usando Chrome para acceder a la página. El ciclo simplemente continúa, tuvo que reiniciar Apache. En el otro extremo, agregar ob_end_flush () en la parte superior resuelve ese problema, además el temporizador es realmente correcto.
ob_end_flush();
ignore_user_abort(true);
set_time_limit(0);
$begin_time = microtime(true);
$elapsed_time = 0;
while(!connection_aborted()) {
echo '' '';
flush();
usleep(1000000);
error_log("looping");
}
$elapsed_time = microtime(true) - $begin_time;
$timer_seconds = $elapsed_time;
error_log(var_export($timer_seconds, true));
$timer_seconds = $elapsed_time / 2;
error_log(var_export($timer_seconds, true));
Si ejecuta esto y mira el registro de errores, verá que $ elpased_time es correcto en la primera ejecución, no es necesario dividirlo también. Según por qué su código se comporta así, no lo sé, ya que ni siquiera funciona en mi máquina.
connection_aborted()
solo puede detectar la desconexión cuando se envía el búfer. Pero flush()
no envía necesariamente el búfer. Entonces, el ciclo sigue iterando hasta que se llene el búfer y, de hecho, se vacíe.
Para obtener más información, consulte las páginas del manual de las funciones nombradas.
Resumen: (este post se volvió épico ya que probé varias avenidas)
PHP toma -típicamente dos- while-iteraciones de bucle para detectar una desconexión o entregar salida. Este retraso podría provenir del software del servidor web, la computadora host, la computadora del cliente y el navegador del cliente, pero luego debería variar según el tiempo de espera por iteración. Lo más probable es que la demora provenga de la ejecución interna o el proceso de salida de PHP (quizás desde un pequeño búfer interno o el proceso de manejo de interrupciones).
Publicación épica:
Contar el tiempo de ejecución desde [Actualizar] o enviar URL no es exactamente un punto de partida preciso; es posible que primero se requiera una cantidad de pasos y se pueda agregar a la demora:
- Se requiere búsqueda de DNS (con sobrecarga de TCP)
- Conexión TCP establecida con el servidor
- El servidor web crea un hilo o un niño
- El servidor web decide cómo tratar la solicitud
- Es posible que PHP deba iniciarse
- PHP puede necesitar convertir su fuente en código de operación
Entonces, en lugar de medir [Refresh] -> [Stop] time y compararlo con el número registrado por PHP, medí la salida visualizada a la salida grabada , lo que reduce la medición de retardo principalmente a PHP (aunque se aplicará el Servidor / Navegador). La secuencia de comandos modificada no se puede ejecutar (finaliza después de un número fijo de iteraciones), borra el almacenamiento en búfer php.ini
predeterminado e informa un recuento de iteraciones en la pantalla y en el archivo de tiempos. Ejecuté el script con varios períodos de $sleep
para ver los efectos. El guión final:
<?php
date_default_timezone_set(''America/Los_Angeles''); //Used by ob apparently
ignore_user_abort(true); //Don''t terminate script because user leaves
set_time_limit(0); //Allow runaway script !danger !danger
while (@ob_end_flush()) {}; //By default set on/4K in php.ini
$start=microtime(true);
$n=1000;
$i=0;
$sleep=100000;// 0.1s
while(!connection_aborted() && $i<$n) {
echo "/n[".++$i."]";flush();
usleep($sleep);
}
$end=microtime(true);
file_put_contents("timing.txt",
"#/$sleep=".($sleep/1000000).
"s/n/ s=$start / e=$end ($i) / d=".($end-$start)."/n",
FILE_APPEND);
?>
Resultados: (múltiples ejecuciones concatenadas, ejecutadas en Firefox)
# On-screen $i / start utime / end utime (current $i) / delta utime
#$sleep=1s
2 / s=1296251342.5729 / e=1296251346.5721 (4) / d=3.999242067337
3 / s=1296251352.9094 / e=1296251357.91 (5) / d=5.000559091568
#$sleep=0.1s
11 / s=1296251157.982 / e=1296251159.2896 (13) / d=1.3075668811798
8 / s=1296251167.5659 / e=1296251168.5709 (10) / d=1.0050280094147
16 / s=1296251190.0493 / e=1296251191.8599 (18) / d=1.810576915741
4 / s=1296251202.7471 / e=1296251203.3505 (6) / d=0.60339689254761
16 / s=1296251724.5782 / e=1296251726.3882 (18) / d=1.8099851608276
#$sleep=0.01s
42 / s=1296251233.0498 / e=1296251233.5217 (44) / d=0.47195816040039
62 / s=1296251260.4463 / e=1296251261.1336 (64) / d=0.68735003471375
150 / s=1296251279.2656 / e=1296251280.901 (152) / d=1.6353850364685
379 / s=1296252444.7587 / e=1296252449.0108 (394) / d=4.2521529197693
#$sleep=0.001s
337 / s=1296251293.4823 / e=1296251294.1515 (341) / d=0.66925406455994
207 / s=1296251313.7312 / e=1296251314.1445 (211) / d=0.41328597068787
792 / s=1296251324.5233 / e=1296251326.0915 (795) / d=1.5682451725006
(Opera no muestra números durante, pero muestra números finales que coinciden aproximadamente)
(Chrome no muestra nada durante / después de la prueba)
(Safari no muestra nada durante / después de la prueba)
(IE no muestra nada durante / después de la prueba)
El primer número en cada línea indica el número que se muestra en la pantalla una vez que se ha presionado [stop] (grabado manualmente).
Algunos puntos:
- Su punto de detención se cuantifica al período de
$sleep
más cercano (1 / 10s en el guión anterior) porque el guión solo verifica al principio de cada iteración, hay alguna variación porque el método deusleep
no es un retraso perfecto. - El navegador y el servidor que está utilizando marcan la diferencia. Las notas de la página de manual de descarga "pueden no ser capaces de anular el esquema de almacenamiento en búfer de su servidor web, y no tiene ningún efecto sobre el almacenamiento en memoria intermedia del lado del cliente en el navegador". Luego entra en más detalles sobre los problemas del servidor y del cliente. [ Servidor : WinXPsp3 / Apache 2.2.17 / PHP 5.3.3 Cliente : WinXPsp3 / FireFox 3.6.13]
Análisis:
En todo menos en el retraso de 0.001, estamos viendo un retraso de 2 iteraciones entre [stop] y PHP atrapándolo (o informes de Firefox o Apache). Con un retraso de 0.001s varía un poco, el promedio es ~ 4 iteraciones o 0.004s - esto probablemente se está acercando al umbral de velocidad de detección.
Cuando el tiempo de demora es de 0.1 so superior, estamos viendo un tiempo de ejecución que coincide estrechamente con $sleep
* {iteraciones registradas}.
Cuando el tiempo de demora es inferior a 0.1 s, estamos viendo demoras de ejecución mayores que el tiempo de suspensión. Esto probablemente se deba al costo de verificar la conexión del cliente, incrementar $i
, enviar texto y vaciar el búfer por iteración. La discrepancia entre el tiempo de ejecución y $i*$sleep
es bastante lineal, sugiriendo que se requiere ~ 0.001s / iteración para completar estas tareas (con un sueño de 0.01s es 0.0008, mientras que un sueño de 0.001s equivale a 0.0010, probablemente como resultado de aumento de MALLOC
/ salida).