2012-02-20 7 views
9

La comprensión de principiante de Node es que si reescribo código síncrono o en línea para utilizar funciones/devoluciones de llamada, puedo asegurarme de que mi código no sea de bloqueo. Tengo curiosidad de cómo funciona esto en términos de la pila de eventos. El ejemplo simple de aquí: Don't understand the callback - Stackoverflow es que esto bloqueará:¿Por qué una función y una devolución de llamada no bloquean en Node.JS?

var post = db.query("select * from posts where id = 1"); 
doSomethingWithPost(post) 
doSomethingElse(); 

Si bien esta costumbre:

callback = function(post){ 
doSomethingWithPost(post) 
} 

db.query("select * from posts where id = 1",callback); 
doSomethingElse(); 

Ok, entiendo que debemos utilizar devoluciones de llamada. Pero en términos de la pila de eventos, ¿por qué funciona esto? Javascript tiene una sola hebra ... en la primera línea de ejemplo uno hace uso de una costosa y bloqueante operación de E/S. La línea 2 no se puede ejecutar hasta que se complete la línea uno. ¿Esto es porque la línea 2 requiere información de la línea 1? ¿O es porque los eventos de E/S son simplemente operaciones de bloqueo fundamentales, lo que significa que se apoderan del control y no lo devuelven hasta que se hace ...

En el segundo ejemplo, la costosa E/S se ha movido a una función, y ahora tenemos una función de devolución de llamada. Ciertamente, la devolución de llamada no se puede ejecutar hasta que se complete la E/S. Esto no cambiaría. Entonces, la diferencia en la cantidad de tiempo que se tarda en ejecutar entre uno y dos debe ser principalmente lo que sucedería si una segunda solicitud llega al servidor.

Si una segunda solicitud golpea el ejemplo uno, no podría procesarse hasta que se haya realizado la solicitud 1 debido a la operación de bloqueo ... pero en el ejemplo dos ... ¿las operaciones en movimiento en funciones generan automáticamente procesos secundarios o actúan como multihilo? Si Javscript tiene un único subproceso, esto aún representaría un problema a menos que haya alguna forma de hacer un procesamiento paralelo. ¿Una función/devolución de llamada solo garantiza ser no bloqueante SI hacemos uso de técnicas sin bloqueo como procesos secundarios, etc.

Respuesta

19

Imagine que está operando la caja registradora en una panadería. Usted maneja sus clientes de forma secuencial y de forma sincrónica, así:

  1. llevar orden
  2. Dile panadería para hornear el pan
  3. Esperar hasta que se cuece el pan dinero
  4. carga
  5. proporcionarle pan
  6. GOTO 1 - próximo cliente

Eso será muy lento. Ahora, en lugar de intentar tomar los pedidos de forma secuencial, pero manejar sus clientes de forma asíncrona:

  1. llevar orden panadero
  2. Tell para hornear el pan, y le notificará cuando haya terminado. Cuando notificado: dinero
    1. carga
    2. proporcionarle pan
  3. GOTO 1 - próximo cliente

ACTUALIZACIÓN: Me refactorizado lo anterior, lo que se asemeja más a una devolución de llamada. Usted, el cajero, tocará el paso 3 inmediatamente después de dar la orden al panadero. Tocará el paso 2.1 cuando el panadero le notifique que el pan está listo.

De esta manera, todavía entregará tanto pan, solo puede vender la cantidad de pan que su panadero pueda hornear. Pero puede tratar con sus clientes de una manera más eficiente, porque en lugar de esperar ociosamente una orden para que regrese, comienza a manejar al próximo cliente.

Ahora, podría hacer todo tipo de detalles sobre esto, y cargar el dinero por adelantado, y decirle al cliente que recoja el pan en el otro extremo del escritorio, o algo por el estilo. Creo que Starbucks está bastante "impactado" de esta manera. El cajero toma la orden, emite una serie de solicitudes de cosas y le dice al cliente que espere hasta que todo esté en el área de recolección. Súper eficiente.

Ahora imagine que su amigo comienza a operar otra caja registradora. Él sigue tu ejemplo asincrónico. ¡Puede manejar más clientes, incluso más rápido! Tenga en cuenta que lo único que tenía que hacer era poner a su amigo allí y darle su flujo de trabajo.

Usted y su amigo son dos bucles de eventos de un solo hilo que se ejecutan en paralelo. Esto es análogo a dos procesos node.js que toman solicitudes. No tiene que hacer nada complejo para paralelizar esto, solo ejecuta un bucle de evento más.

Así que, no, "mover operaciones a funciones" no "genera automáticamente procesos secundarios". Son más parecidos a las alarmas: cuando esto termine, notifíqueme y permítame continuar en este momento, "este punto" es el código en su devolución de llamada. Pero la devolución de llamada seguirá ejecutándose en el mismo proceso y con el mismo hilo.

Ahora, node.js también opera un grupo de subprocesos interno para IO. Esto está abstraído de usted: para continuar la analogía de la panadería, digamos que tiene un "grupo de panaderos" de panaderos; para usted, de pie frente a la caja registradora, no tiene que saber nada al respecto. Usted simplemente les da la orden ("un pan de masa fermentada") y entrega ese pedido cuando se le notifica que se ha terminado. Pero los panaderos hornean su pan en paralelo, en su propio "grupo de panaderos".

+1

Gracias por la gran analogía. Para mayor aclaración. En este ejemplo, un cajero toma una orden y la devuelve a la cocina, luego puede ir y procesar otra orden. Ahora, quien toma la orden aquí es la función principal del servidor ... y la cocina son todas las funciones delegadas con sus propias devoluciones de llamada. Si la función de servidor delega en una función y les devuelve una devolución de llamada y dice ... vuelve a consultarme cuando haya terminado ... Si a la cocina no se le da un medio para generar un proceso secundario ... ¿no se bloqueará hasta que se realice la devolución de llamada? ¿se ha enviado? – Inc1982

+0

La cocina tiene un grupo de subprocesos interno. Por lo tanto, tendrá algunos hilos para distribuir las tareas. Pero esto está abstraído de usted en Node.js, y nada de eso se ejecuta en su ciclo de eventos, por lo que no afectará en absoluto su código. Si realiza un cálculo intensivo de CPU en su propio código, eso bloqueará _el ciclo completo del evento_ (por ejemplo, digamos que el cajero decide hornear uno de los panes él mismo), durante este tiempo, no puede tomar ningún pedido nuevo). –

+1

¿Está diciendo que para una función estándar/nodo de devolución de llamada puede usar un grupo de subprocesos interno para garantizar el rendimiento asincrónico pero que para una llamada costosa, tendríamos que configurar un trabajador como lo haría el ejecutivo? Si es así, ¿cómo sabría el umbral de 'caro'? Ese parece ser un punto clave entonces. – Inc1982

3

No soy bueno en inglés, así que no puedo entender lo que quiere decir exactry. Pero puedo decir que 'multi thread' y 'asynchronous' son términos similares pero diferentes. Incluso si el hilo individual puede funcionar como 'asíncrono'.

This document no es para nodo (es un marco asincrónico de python "retorcido") pero podría ser útil para usted.

lo siento por mi pobre inglés.

+0

Este es un gran documento que proporcionó, ¡muchas gracias! Muy claro. – Inc1982

Cuestiones relacionadas