2011-02-07 19 views
7

He estado trabajando en la implementación de un sistema bastante complejo en JavaScript que necesita simular, entre otras cosas, procesos multiproceso. En un proceso real multiproceso (como un hilo del núcleo) es posible cambiar entre hilos mediante el cambio de contexto. Esto funciona porque puede almacenar el contador de programa del proceso actual y registrarse en una estructura temporal, restaurar el contador del programa y registrarse para algún otro proceso, y luego reanudar donde lo dejó en el proceso anterior.Simulando interruptores de contexto en JavaScript?

Tengo curiosidad si es posible tener algo similar a esto en JavaScript. Actualmente no sé cómo hacer esto y he estado diseñando el sistema usando multitareas cooperativas. En particular, cualquier "función" que deseo ejecutar en el simulador de subprocesos múltiples se divide en una matriz de funciones. Para ejecutar la "función", repito a través de la matriz de funciones, ejecutándolas en orden mientras mantengo un "contador de programa" cuya función ejecutar a continuación. Esto me permite simular un cambio de contexto llamando a una de las funciones de la matriz, esperando que la función regrese, y luego cambiando a otra serie de funciones que deben ejecutarse.

Mi enfoque actual funciona, pero es difícil escribir código en este sistema. Cada función tiene que indicar específicamente cuándo se puede interrumpir, y dado que las funciones en la matriz están todas separadas, la lógica para comunicar datos entre diferentes partes de la función es complicada. Esperaba conseguir algo más cercano a trabajar en múltiples tareas preventivas.

Mi pregunta es: ¿es posible ejecutar una función de JavaScript arbitraria de manera que pueda ser suspendida y reanudada por una fuente externa?

+3

Mención obligatoria de [Trabajadores web] (https://developer.mozilla.org/En/Using_web_workers) cuando alguien usa JavaScript y multihilo en la misma oración. –

Respuesta

4

Comprobar StratifiedJS cabo

+1

stratifiedjs.org dice: "StratifiedJS amplía el lenguaje JavaScript con un pequeño número de palabras clave para la programación simultánea. Le permite expresar el flujo de control asincrónico en un estilo secuencial sencillo y estructurado". Suena como lo que necesitas – tomg

+0

@ qwertymk- Esto se ve muy bien, pero desafortunadamente (por lo que puedo decir) no es compatible con ningún navegador web, lo que en cierto modo frustra el propósito. Sin embargo, este es un gran enlace y ¡gracias por compartirlo! – templatetypedef

+0

@templatetypedef es compatible con navegadores web. Vaya a [su consola] (http://onilabs.com/docs#tryit) e intente ejecutar esto: 'console.log ('waiting 3 seconds ....'); mantener (3000); console.log ('done') ' – qwertymk

3

primer lugar, es importante mencionar que JavaScript está completamente solo subproceso. Emular multi-threading realmente no es el camino a seguir. Es mucho mejor confiar en eventloops.

Como los trabajadores web mencionados podrían ser utilizados, pero no hay realmente un cumplimiento de navegador cruzado para ellos, así que ignoraré a los trabajadores web. Tampoco puedes hacer ninguna manipulación DOM con trabajadores web.

Yo diría que echa un vistazo a node.js para razonar detrás de por qué los bucles de eventos son una buena alternativa al multi-threading. Creo que toca bastante bien por qué es una buena alternativa en este video.

Entonces, en lugar de tener una serie de funciones e iterar sobre ellas, en su lugar puede crear un evento y vincular un conjunto de funciones a ellas y desencadenar dicho evento. Se puede encontrar una implementación de eventos muy ligera en backbone.js.

No puede simplemente pausar un hilo en JavaScript porque solo hay uno. No hay forma de suspender o reanudar una función sin una función que tenga puntos.

Solo hay una forma de emular esto. Escriba un analizador de JavaScript que rasgue su JavaScript bien diseñado y construya un sistema que le permita suspender y reanudar su JavaScript.

Tomemos por ejemplo esta función

function(i) { 
    j = i + 1; 
    console.log(j); 
    return foo(j); 
} 

y la convierte en este

var bar = function(i) { 
    var r = {}; 
    var j = i + 1; 
    var f = function() { 
     console.log(j); 
     var g = function() { 
       return foo(j); 
     }; 
     onNext(g, arguments.callee, this, r); 
    }; 
    onNext(f, arguments.callee, this); 
    return r; 
} 

el va a necesitar extender Función con .suspend y .resume

Function.prototype.suspend = function() { 
    this.__suspended = true; 
} 

Function.prototype.resume = function() { 
    this.__suspended = false; 
} 

function onNext(callback, function, context, returnObj) { 
    if (!function.__suspended) { 
      var cb = function() { 
       Backbone.Events.unbind("run", cb); 
       returnObj.r = callback.call(this); 
      } 
      Backbone.Events.bind("run", cb); 
    } 
} 

setInterval(function() { 
    Backbone.Events.trigger("run"); 
}, 5); 

También vas a tiene que reemplazar todas las referencias a var a = b() con

callFunctionAsync(b, context, args, function(return) { 
    var a = return; 
    ... 
}); 

Dejaré la implentación a su medida. Por el momento, todas las funciones devuelven un objeto r y solo cuando r.r se establece en un valor, se "devuelve". Así que simplemente revise el bucle de evento si ya ha "regresado" comprobando si r.r está configurado y si ha activado la función de devolución de llamada asincrónica.

Hola y mira lo que tenemos. Estamos emulando hilos ejecutándolos alrededor del ciclo de eventos. Es mucho mejor utilizar el bucle de evento de forma nativa en su código en lugar de emular hilos a través de él.

Básicamente, obtenga su función para ejecutar la siguiente línea de su código cuando recorra nuevamente el ciclo de eventos. Y verifique si la "función" en particular se suspende o reanuda cuando recorre su evento.

No implemente burbujeando el retorno de las funciones de nuevo a la "función" en aras de la brevedad. Esto no debería ser demasiado difícil de emular.

O utilice el bucle de evento directamente o utilice métodos de hebras falsas y obtenga un compilador para compilar su código para que no se vea horrible cuando lo codifica.

Si causa cerraduras muertas, buena suerte para usted.

+0

@ Raynos- ¡Gracias por las sugerencias! Mi implementación actual no utiliza tanto los hilos como la implementación de un sistema que requiere subprocesamiento (específicamente, la JVM), así que realmente no tengo otra opción aquí. Actualmente estoy usando eventos para hacer esto: tengo un tiempo de espera de ventana que se dispara periódicamente para ejecutar más código. Tu sugerencia para que cada función registre una continuación es realmente genial. Estoy pensando que podría compilar un compilador cruzado que autogenera este código para mí. Muchas gracias por su consejo! – templatetypedef

+0

@templatetypedef Si está implementando el enhebrado para la JVM, ¿por qué necesita que se enhebre su javascript? ¿Está permitiendo que los usuarios ejecuten código de JavaScript en la parte superior de su JVM? Simplemente parece tan equivocado hacerlo de esta manera y es muy fácil hacer que los hilos estén equivocados y romper el estado completamente.Cualquier parte interna de la JVM que requiera enhebrado puede implementarse internamente en su javascript utilizando bucles de eventos. – Raynos

+0

@ Raynos- Es al revés: estoy usando JavaScript para implementar la JVM. :-) Es para un proyecto académico. El desafío es cómo implementar mejor los subprocesos de nivel de JVM dentro de JavaScript y, al mismo tiempo, permitir que las funciones nativas de Java se implementen de forma nativa en JavaScript. – templatetypedef

Cuestiones relacionadas