w3schools tag tab color attribute javascript multithreading performance google-chrome web-worker

javascript - tag - ¿Por qué el rendimiento del trabajador web disminuye bruscamente después de 30 segundos?



title html w3schools (2)

Estoy intentando mejorar el rendimiento de un script cuando se ejecuta en un trabajador web. Está diseñado para analizar grandes archivos de texto en el navegador sin fallar. Todo funciona bastante bien, pero me doy cuenta de una gran diferencia en el rendimiento de los archivos grandes cuando utilizo un trabajador web.

Así que realicé un experimento sencillo. Ejecuté el script en la misma entrada dos veces. La primera ejecución ejecutó el script en el hilo principal de la página (sin trabajadores web). Naturalmente, esto hace que la página se congele y deje de responder. Para la segunda ejecución, ejecuté el script en un trabajador web.

Para archivos pequeños en este experimento (<~ 100 MB), la diferencia de rendimiento es despreciable. Sin embargo, en archivos grandes, el análisis tarda aproximadamente 20 veces más en el subproceso de trabajo:

Se espera la línea azul. El análisis del archivo solo debería tomar unos 11 segundos, y el rendimiento es bastante constante:

La línea roja es el rendimiento dentro del trabajador web. Es mucho más sorprendente:

La línea irregular durante los primeros 30 segundos es normal (la causa es el ligero retraso en el envío de los resultados al subproceso principal después de analizar cada fragmento del archivo). Sin embargo, el análisis se ralentiza bastante bruscamente a los 30 segundos. (Tenga en cuenta que solo uso un solo trabajador web para el trabajo; nunca más de un hilo de trabajador a la vez).

He confirmado que el retraso no está en enviar los resultados al hilo principal con postMessage() . La desaceleración se encuentra en el bucle estrecho del analizador, que es totalmente síncrono. Por razones que no puedo explicar, ese bucle se ralentiza drásticamente y se vuelve más lento con el tiempo después de 30 segundos.

Pero esto solo sucede en un trabajador web. Ejecutar el mismo código en el subproceso principal, como se ha visto anteriormente, se ejecuta de manera muy fluida y rápida.

¿Por qué está pasando esto? ¿Qué puedo hacer para mejorar el rendimiento? (No espero que nadie entienda completamente las más de 1,200 líneas de código en ese archivo. Si lo hace, es increíble, pero tengo la sensación de que está más relacionado con los trabajadores web que con mi código, ya que funciona bien en su mayoría hilo.)

Sistema: estoy ejecutando Chrome 35 en Mac OS 10.9.4 con 16 GB de memoria; Intel Core i7 de 2,7 GHz de cuatro núcleos con 256 KB de caché L2 (por núcleo) y L3 de 6 MB. Los fragmentos de archivos son de unos 10 MB de tamaño.

Actualización: lo probé en Firefox 30 y no experimentó la misma ralentización en un subproceso de trabajo (pero fue más lento que Chrome cuando se ejecutó en el subproceso principal). Sin embargo, intentar el mismo experimento con un archivo aún más grande (aproximadamente 1 GB) produjo una ralentización significativa después de unos 35-40 segundos (parece).


¿En qué hardware estás ejecutando? Es posible que se esté ejecutando en problemas de memoria caché con su CPU. Por ejemplo, si la memoria caché de la CPU es de 1 MB por núcleo (solo un ejemplo) y comienza a tratar de trabajar con datos que reemplazan la memoria caché (se pierde la memoria caché), sufrirá ralentizaciones; esto es bastante común en los sistemas MT. Esto es común en las transferencias de IO también. También estos sistemas tienden a tener algunas sobrecargas de sistema operativo para los contextos de subprocesos también. Por lo tanto, si se generan muchos subprocesos, es posible que pases más tiempo gestionando los contextos que lo que el subproceso está "haciendo trabajo". Todavía no he mirado su código, por lo que podría estar muy lejos, pero mi suposición es sobre el problema de la memoria solo por lo que está haciendo su aplicación. :)

Oh. Como arreglar. Intente hacer los bloques de ejecución pequeños trozos individuales que coincidan con el hardware. Minimice la cantidad de subprocesos en uso al mismo tiempo: intente mantenerlos 2-3 veces la cantidad de núcleos que tiene en el hardware (esto realmente depende del tipo de hw que tenga). Espero que ayude.


Tyler Ault sugirió una posibilidad en Google+ que resultó ser muy útil.

FileReaderSync que el uso de FileReaderSync en el subproceso de trabajo (en lugar del FileReader simple y asíncrono) no ofrecía una oportunidad para que se produjera la recolección de basura.

Cambiar el subproceso de trabajo para usar FileReader forma asíncrona (lo que intuitivamente parece ser un paso de rendimiento hacia atrás ) aceleró el proceso hasta solo 37 segundos, justo donde esperaba que fuera.

No he vuelto a tener noticias de Tyler y no estoy del todo seguro de entender por qué la recolección de basura sería la culpable, pero algo acerca de FileReaderSync estaba ralentizando drásticamente el código.