¿Cuáles son los inconvenientes de hacer una implementación de tiempo de ejecución de JavaScript de múltiples subprocesos? [cerrado]

51

He estado trabajando en una implementación de ejecución de JavaScript multihebra durante la semana pasada. Tengo una prueba de concepto hecha en C ++ usando JavaScriptCore y boost.

La arquitectura es simple: cuando el tiempo de ejecución termina de evaluar la secuencia de comandos principal, se inicia y se une a un grupo de subprocesos, que comienza a seleccionar tareas de una cola de prioridad compartida, si dos tareas intentan acceder a una variable simultáneamente, se marca como atómica y contender por el acceso.

ElproblemaesquecuandolemuestroestediseñoaunprogramadordeJavaScript,recibocomentariosmuynegativosynotengoideadeporqué.Inclusoenprivado,todosdicenqueJavaScriptestádestinadoaserdeunsolohilo,quelasbibliotecasexistentestendríanquevolveraescribirse,yquelosgremlinsengendraránysecomeránatodoslosseresvivossicontinúotrabajandoenesto.

OriginalmentetambiéntuveunaimplementaciónnativadeCoroutine(usandocontextosdeboost),perotuvequedeshacermedeella(JavaScriptCoreespedantesobrelapila),ynoqueríaarriesgarsuira,asíquedecidínomencionarit.

¿Quépiensas?¿JavaScriptestádestinadoaserdeunsolohilo,ydebedejarsesolo?¿PorquétodosestánencontradelaideadeuntiempodeejecucióndeJavaScriptconcurrente?

Editar:elproyectoahoraestáen GitHub , experimenta con él y hazme saber lo que piensas.

La siguiente es una imagen de las promesas que se ejecutan en todos los núcleos de CPU en paralelo y sin contención:

    
pregunta voodooattack 12.04.2016 - 06:31

8 respuestas

70

1) El multiproceso es extremadamente difícil, y desafortunadamente la forma en que presentaste esta idea implica que estás subestimando lo difícil que es.

En este momento, suena como si simplemente estuvieras "agregando hilos" al idioma y preocupándote de cómo hacerlo correcto y tener un desempeño posterior. En particular:

  

si dos tareas intentan acceder a una variable al mismo tiempo, se marca como atómica y compiten por acceder.
  ...
  Estoy de acuerdo en que las variables atómicas no resolverán todo, pero trabajar en una solución para el problema de sincronización es mi próximo objetivo.

Agregar subprocesos a Javascript sin una "solución para el problema de sincronización" sería como agregar enteros a Javascript sin una "solución para el problema de la suma". Es tan fundamental para la naturaleza del problema que, básicamente, no tiene sentido discutir si vale la pena agregar el multihilo sin una solución específica en mente, sin importar lo mal que lo deseemos.

Además, hacer que todas las variables sean atómicas es el tipo de cosa que probablemente haga que un programa de subprocesos múltiples sea peor que su contraparte de un solo hilo, lo que hace que sea aún más importante probar el desempeño en programas más realistas y mira si estás ganando algo o no.

Tampoco me queda claro si está intentando mantener los hilos ocultos para el programador de node.js o si planea exponerlos en algún momento, creando un nuevo dialecto de Javascript para la programación de múltiples subprocesos. Ambas opciones son potencialmente interesantes, pero parece que aún no has decidido a cuál te diriges.

Por lo tanto, en este momento, le está pidiendo a los programadores que consideren cambiar de un entorno de un solo hilo a un nuevo entorno multihilo que no tiene solución para el problema de sincronización y no hay pruebas de que mejore el rendimiento en el mundo real, y aparentemente no hay un plan para resolverlo. esas cuestiones.

Probablemente por eso la gente no te toma en serio.

2) La simplicidad y robustez del bucle de evento único es una ventaja de enorme .

Los programadores de Javascript saben que el lenguaje Javascript es "seguro" frente a las condiciones de la carrera y otros errores extremadamente insidiosos que afectan a toda la programación multiproceso genuina. El hecho de que necesiten argumentos sólidos para convencerlos de que renuncien a la seguridad no los hace con una mentalidad cerrada, sino que los hace responsables.

A menos que pueda mantener esa seguridad, cualquier persona que quiera cambiar a un nodo multiproceso.js probablemente sería mejor que cambie a un lenguaje como Go que está diseñado desde cero para aplicaciones de multiproceso.

3) Javascript ya es compatible con "subprocesos en segundo plano" (WebWorkers) y programación asíncrona sin exponer directamente la gestión de subprocesos al programador.

Esas funciones ya resuelven muchos de los casos de uso comunes que afectan a los programadores de Javascript en el mundo real, sin renunciar a la seguridad del bucle de un solo evento.

¿Tiene algún caso de uso específico en mente que estas características no resuelven y que los programadores de Javascript desean una solución? Si es así, sería una buena idea presentar su node.js multiproceso en el contexto de ese caso de uso específico.

P.S. ¿Qué me convencería a yo para intentar cambiar a una implementación de node.js multiproceso?

Escriba un programa no trivial en Javascript / node.js que piense que se beneficiaría de un multihilo genuino. Realice pruebas de rendimiento en este programa de ejemplo en el nodo normal y en su nodo multiproceso. Demuéstrame que tu versión mejora en gran medida el rendimiento en tiempo de ejecución, la capacidad de respuesta y el uso de múltiples núcleos, sin introducir errores ni inestabilidad.

Una vez que hayas hecho eso, creo que verás gente mucho más interesada en esta idea.

    
respondido por el Ixrec 12.04.2016 - 11:07
16

Solo adivinando aquí para demostrar un problema en su enfoque. No puedo probarlo con la implementación real ya que no hay ningún enlace en ningún lugar ...

Yo diría que es porque los invariantes no siempre se expresan por el valor de una variable, y 'una variable' no es suficiente para ser el alcance de un bloqueo en el caso general. Por ejemplo, imagine que tenemos un invariante que a+b = 0 (el saldo de un banco con dos cuentas). Las dos funciones a continuación aseguran que el invariante siempre se mantenga al final de cada función (la unidad de ejecución en JS de un solo hilo).

function withdraw(v) {
  a -= v;
  b += v;
}
function deposit(v) {
  b -= v;
  a += v;
}

Ahora, en tu mundo multiproceso, ¿qué sucede cuando dos subprocesos ejecutan withdraw y deposit al mismo tiempo? Gracias, Murphy ...

(Es posible que tenga un código que trate a + = y - = especialmente, pero eso no sirve de ayuda. En algún momento, tendrá un estado local en una función y no podrá "bloquear" dos variables al mismo tiempo. tu invariante será violada.)

EDITAR: si su código es semánticamente equivalente al código Go en enlace , mi comentario es correcto; -)

    
respondido por el thriqon 12.04.2016 - 09:43
15

Hace aproximadamente una década, Brendan Eich (el inventor de JavaScript) escribió un ensayo llamado Threads Suck , que es definitivamente uno de los pocos documentos canónicos de la mitología del diseño de JavaScript.

Si es correcta es otra pregunta, pero creo que tuvo una gran influencia en cómo la comunidad de JavaScript piensa acerca de la concurrencia.

    
respondido por el Erik Pukinskis 12.04.2016 - 08:20
9

El acceso atómico no se traduce en un comportamiento seguro para subprocesos.

Un ejemplo es cuando una estructura de datos global no es válida durante una actualización, como volver a copiar un mapa de hash (al agregar una propiedad a un objeto, por ejemplo) o al ordenar una matriz global. Durante ese tiempo no puedes permitir que ningún otro hilo acceda a la variable. Básicamente, esto significa que necesita detectar todos los ciclos de lectura-actualización-escritura y bloquearlos. Si la actualización no es trivial, terminará en detener el territorio del problema.

Javascript se ha enlazado de forma única y en un espacio aislado desde el principio y todo el código está escrito teniendo en cuenta estas suposiciones.

Esto tiene una gran ventaja con respecto a los contextos aislados y al permitir que 2 contextos separados se ejecuten en diferentes hilos. También significa que las personas que escriben javascript no necesitan saber cómo lidiar con las condiciones de la carrera y varios otros pitfals de múltiples subprocesos.

    
respondido por el ratchet freak 12.04.2016 - 11:16
6

¿Su enfoque mejorará significativamente el rendimiento?

Dudoso. Realmente necesitas probar esto.

¿Su enfoque lo hará más fácil / rápido para escribir código?

Definitivamente no, el código multiproceso es muchas veces más difícil de entender que el código de un solo hilo.

¿Su enfoque será más sólido?

Los puntos muertos, las condiciones de la carrera, etc. son una pesadilla para solucionar.

    
respondido por el Phil Wright 12.04.2016 - 08:14
2

Su implementación no se trata solo de introducir la concurrencia, sino de la introducción de una forma específica de implementar la concurrencia, es decir, la concurrencia por estado mutable compartido. En el transcurso de la historia, las personas han usado este tipo de concurrencia y esto ha llevado a muchos tipos de problemas. Por supuesto, puede crear programas simples que funcionen perfectamente con el uso de la concurrencia de estado mutable compartida, pero la prueba real de cualquier mecanismo no es lo que puede hacer, sino que puede escalarse a medida que el programa se vuelve complejo y se agregan más funciones al programa. Recuerde que el software no es una cosa estática que usted construye una vez y se termina con él, sino que sigue evolucionando con el tiempo y si algún mecanismo o concepto no puede hacer frente a la evolución del software, solo generará nuevos problemas y esto es exactamente Lo que la historia nos ha enseñado sobre la concurrencia de memoria mutable compartida.

Puede ver otros modelos de concurrencia (por ejemplo, paso de mensajes) para ayudarlo a determinar qué tipo de beneficios proporcionan esos modelos.

    
respondido por el Ankur 12.04.2016 - 07:54
1

Esto es necesario. La falta de un mecanismo de concurrencia de bajo nivel en el nodo js limita sus aplicaciones en campos como matemática y bioinformática, etc. Además, la concurrencia con hilos no necesariamente entra en conflicto con el modelo de concurrencia predeterminado utilizado en el nodo. Existen semánticas bien conocidas para los subprocesos en un entorno con un bucle de eventos principal, como los marcos ui (y los nodejs), y aunque definitivamente son demasiado complejos para la mayoría de las situaciones, todavía tienen usos válidos.

Claro, tu aplicación web promedio no requerirá subprocesos, pero intenta hacer algo un poco menos convencional, y la falta de una primitiva de concurrencia de bajo nivel de sonido te llevará rápidamente a otra cosa que sí la ofrezca.

    
respondido por el dryajov 12.04.2016 - 09:17
0

Realmente creo que es porque es una idea diferente y poderosa. Vas contra los sistemas de creencias. Las cosas son aceptadas o populares a través de los efectos de la red, no sobre la base del mérito. Además, nadie quiere adaptarse a una nueva pila. Las personas rechazan automáticamente las cosas que son demasiado diferentes.

Si puedes encontrar una manera de convertirlo en un módulo npm normal que parezca poco probable, entonces es posible que algunas personas lo utilicen.

    
respondido por el Jason Livesay 12.04.2016 - 07:41

Lea otras preguntas en las etiquetas