2009-02-28 23 views
26

¿La llamada asincrónica siempre crea un nuevo hilo?¿Una llamada asincrónica siempre crea/llama un nuevo hilo?

Ejemplo:

Si JavaScript es el único subproceso entonces ¿cómo puede hacer una devolución de datos asincrónica? ¿Está realmente bloqueando hasta que reciba una devolución de llamada? Si es así, ¿se trata realmente de una llamada asincrónica?

Respuesta

50

Esta es una pregunta interesante.

programación asíncrona es un paradigma de programación que es principalmente roscado único, es decir, "después de un hilo de ejecución continua".

Usted se refiere a Javascript, por lo que vamos a discutir que el lenguaje, en el medio de un navegador web. Un navegador web ejecuta un único hilo de ejecución javascript en cada ventana, maneja eventos (como onclick = "someFunction()") y conexiones de red (como llamadas xmlhttprequest).

<script> 
function performRequest() { 
    xmlhttp.open("GET", "someurl", true); 
    xmlhttp.onreadystatechange = function() { 
    if (xmlhttp.readyState == 4) { 
     alert(xmlhttp.responseText); 
    } 
    } 
    xmlhttp.send(sometext); 
} 
</script> 
<span onclick="performRequest()">perform request</span> 

(Este es un ejemplo que no funciona, para la demostración de conceptos solamente).

Con el fin de hacer todo de una manera asíncrona, el subproceso de control tiene lo que se conoce como un 'bucle principal'. Un bucle principal se ve algo así como esto:

while (true) { 
    event = nextEvent(all_event_sources); 
    handler = findEventHandler(event); 
    handler(event); 
} 

Es importante tener en cuenta que esto no es un 'bucle ocupado'. Esto es como un hilo de dormir, esperando que ocurra la actividad. La actividad podría ser ingresada por el usuario (movimiento del mouse, un clic de botón, escritura) o podría ser una actividad de red (la respuesta del servidor).

Así en el ejemplo anterior,

  1. Cuando el usuario hace clic en el lapso, se generaría un evento buttonClicked, findEventHandler() encontraría el evento onclick en la etiqueta span, y después de que manipulador sería llamado con el evento.
  2. Cuando se crea la solicitud xmlhttp, se agrega a la lista all_event_sources de orígenes de eventos.
  3. Después de que la función performRequest() retorna, el mainloop está esperando en el paso nextEvent() esperando una respuesta. En este punto, no hay nada que bloquee el manejo de otros eventos.
  4. Los datos vuelven del servidor remoto, nextEvent() devuelve el evento de red, el controlador de eventos es el método onreadystatechange(), se invoca ese método y se activa un diálogo de alerta().

Vale la pena señalar que alert() es un cuadro de diálogo de bloqueo. Mientras ese diálogo está activo, no se pueden procesar más eventos. Es una excentricidad del modelo de páginas web javascript que tenemos un método disponible que bloqueará la ejecución posterior dentro del contexto de esa página.

+0

sugieren una edición de la respuesta "No vale nada" es diferente a "vale la pena ver" que creo que es su intención. Solo para evitar confusiones para los lectores – MadMurf

+0

@MadMurf: lo noté ... y lo solucioné. – mpen

+0

>> La programación asíncrona es un paradigma de programación que es principalmente de subprocesos << - No intento ser pedante aquí, pero no veo cómo esta afirmación es verdadera. ¿La programación asíncrona implica algo acerca de los hilos, y mucho menos de uno contra varios? – Lee

15

modelo El Javascript es único subproceso. Una llamada asincrónica es no un nuevo hilo, sino que interrumpe un hilo existente. Es análogo a las interrupciones en un kernel.

Sí, tiene sentido tener llamadas asíncronas con un solo hilo. He aquí cómo pensar sobre esto: cuando llama a una función dentro de un único hilo, el estado del método actual se inserta en una pila (es decir, variables locales). La subrutina se invoca y finalmente regresa, momento en el que el estado original se elimina de la pila.

Con una devolución de llamada asíncrona, sucede lo mismo! La diferencia es que el sistema invoca la subrutina, no el código actual que invoca una subrutina.

+1

>> Una llamada asíncrona no es un nuevo hilo << - Creo que esta es una declaración engañosa. No tengo conocimiento de nada que impida a JS atender una solicitud XHR con nuevos hilos. Creo que quiere decir que la especificación no garantiza ni sugiere un nuevo hilo, pero definitivamente puede ser la forma en que el sistema lo implemente. – Lee

4

En muchas aplicaciones GUI, una llamada asíncrona (como invokeLater de Java) simplemente añade el objeto Ejecutable a su cola de hilo de interfaz gráfica de usuario. El hilo de GUI ya está creado y no crea un nuevo hilo. Pero los hilos ni siquiera son estrictamente necesarios para un sistema asíncrono. Tomemos, por ejemplo, libevent, que usa select/poll/kqueue, etc. para hacer llamadas no bloqueadas a sockets, que luego activan devoluciones de llamada a su código, completamente sin hilos.

5

Un par de notas acerca de JavaScript en particular:

XMLHttpRequest s son no-bloqueo por defecto. El método send() regresa inmediatamente después de que la solicitud se haya transmitido a la pila de red subyacente. Una respuesta del servidor programará una invocación de su devolución de llamada en el ciclo de eventos como se discutió en las otras respuestas excelentes.

Esto no requiere un hilo nuevo. La API de socket subyacente es seleccionable, similar a java.nio.channels en Java.

Es posible construir síncronosXMLHttpRequest objetos haciendo pasar false como tercer parámetro a open(). Esto hará que el método send() se bloquee hasta que se reciba una respuesta del servidor, colocando el bucle de eventos a merced de la latencia de la red y posiblemente colgando el navegador hasta el tiempo de espera de la red. Esto es un Bad Thing ™.

Firefox 3.5 introducirá el HTML multiproceso honesto con la clase Worker. El código de fondo se ejecuta en un entorno completamente separado y se comunica con la ventana del navegador mediante la programación de devoluciones de llamada en el bucle de evento.

+0

cuando dijo que 'Una respuesta del servidor programará una invocación de su devolución de llamada en el bucle de evento', ¿qué hilo coloca un evento en el bucle de evento para hacer que se invoque la devolución de llamada? – Yiling

+1

@Yiling El evento se crea mediante un subproceso de E/S interno al navegador, no un subproceso que ejecuta JavaScript. – Matthew

2

No, pero habrá más de un hilo involucrado.

Una llamada asincrónica podría iniciar otro hilo para hacer el trabajo, o podría publicar un mensaje en una cola en otro hilo que ya esté ejecutándose. La persona que llama continúa y el llamado vuelve a llamar una vez que procesa el mensaje.

Si desea realizar una llamada síncrona en este contexto, debe publicar un mensaje y esperar activamente a que se realice la devolución de llamada.

Por lo tanto, en resumen: se tratará de más de un hilo, pero no necesariamente crea un hilo nuevo.

2

No sé acerca de javascript, pero por ejemplo en el mundo de Windows Forms, las invocaciones asincrónicas se pueden realizar sin múltiples hilos. Esto tiene que ver con la forma en que funciona Windows Message Pump. Básicamente, una aplicación de Windows Forms configura una cola de mensajes a través de la cual Windows coloca mensajes notificándolo sobre eventos. Por ejemplo, si mueve el mouse, los mensajes se colocarán en esa cola. La aplicación Windows Forms estará en un bucle sin fin que consumirá todos los mensajes que se le envíen. De acuerdo con lo que contenga cada mensaje, moverá las ventanas, las volverá a pintar o incluso invocará métodos definidos por el usuario, entre otras cosas. Los delegados identifican las llamadas a los métodos. Cuando la aplicación encuentra una instancia de delegado en la cola, felizmente invoca el método al que hace referencia el delegado.

Por lo tanto, si se encuentra en un método haciendo algo y desea generar un trabajo asincrónico sin crear un nuevo hilo, todo lo que tiene que hacer es colocar una instancia delegada en la cola, utilizando el método Control.BeginInvoke. Ahora, esto no es en realidad multiproceso, pero si arrojas pequeñas piezas de trabajo a la cola, se verá como multiproceso. Si, por otro lado, le da un método lento para ejecutar, la aplicación se congelará hasta que se complete el método, que se verá como una aplicación atascada, aunque esté haciendo algo.

Cuestiones relacionadas