¿Qué es la E / S sin bloqueo o asincrónica en Node.js?

136

En el contexto de los motores Javascript del lado del servidor, ¿qué son las E / S sin bloqueo o las E / S asíncronas? Veo que esto se menciona como una ventaja sobre las implementaciones del lado del servidor Java.

Anand
fuente
3
Es útil pensar en las etiquetas de script en el entorno del navegador para comprender este concepto. Zakas tiene un gran artículo sobre esto: las primeras secciones deberían ser suficientes para explicar el concepto de bloqueo: nczonline.net/blog/2010/08/10/what-is-a-non-blocking-script
netpoetica

Respuestas:

317

Sincrónico vs Asincrónico

La ejecución síncrona generalmente se refiere a la ejecución de código en secuencia. La ejecución asincrónica se refiere a la ejecución que no se ejecuta en la secuencia que aparece en el código. En el siguiente ejemplo, la operación síncrona hace que las alertas se disparen en secuencia. En la operación asíncrona, aunque alert(2)parece ejecutarse en segundo lugar, no lo hace.

Sincrónico: 1,2,3

alert(1);
alert(2);
alert(3);

Asincrónico: 1,3,2

alert(1);
setTimeout(() => alert(2), 0);
alert(3);

Bloqueo vs No bloqueo

El bloqueo se refiere a operaciones que bloquean la ejecución posterior hasta que finalice esa operación. Sin bloqueo se refiere al código que no bloquea la ejecución. En el ejemplo dado, localStoragees una operación de bloqueo ya que detiene la ejecución para leer. Por otro lado, fetches una operación sin bloqueo ya que no se detiene alert(3)durante la ejecución.

// Blocking: 1,... 2
alert(1);
var value = localStorage.getItem('foo');
alert(2);

// Non-blocking: 1, 3,... 2
alert(1);
fetch('example.com').then(() => alert(2));
alert(3);

Ventajas

Una ventaja de las operaciones asincrónicas sin bloqueo es que puede maximizar el uso de una sola CPU y memoria.

Ejemplo de bloqueo síncrono

Un ejemplo de operaciones de bloqueo síncrono es cómo algunos servidores web como los de Java o PHP manejan las solicitudes de IO o de red. Si su código se lee desde un archivo o la base de datos, su código "bloquea" todo después de su ejecución. En ese período, su máquina retiene la memoria y el tiempo de procesamiento de un hilo que no está haciendo nada .

Para atender otras solicitudes mientras el hilo se ha estancado depende de su software. Lo que la mayoría del software de servidor hace es generar más hilos para atender las solicitudes adicionales. Esto requiere más memoria consumida y más procesamiento.

Ejemplo asincrónico sin bloqueo

Los servidores asíncronos que no bloquean, como los creados en Node, solo usan un hilo para atender todas las solicitudes. Esto significa que una instancia de Node aprovecha al máximo un solo hilo. Los creadores lo diseñaron con la premisa de que las operaciones de red y E / S son el cuello de botella.

Cuando las solicitudes llegan al servidor, se atienden de una en una. Sin embargo, cuando el código revisado necesita consultar la base de datos, por ejemplo, envía la devolución de llamada a una segunda cola y el subproceso principal continuará ejecutándose (no espera). Ahora, cuando la operación DB se completa y regresa, la devolución de llamada correspondiente se retiró de la segunda cola y se puso en cola en una tercera cola donde están pendientes de ejecución. Cuando el motor tiene la oportunidad de ejecutar otra cosa (como cuando se vacía la pila de ejecución), recoge una devolución de llamada de la tercera cola y la ejecuta.

Joseph
fuente
55
No estoy seguro de entender su segundo párrafo en Bloqueo en PHP . ¿Está diciendo que, "mientras que PHP normalmente se bloquearía en IO, no lo hace porque el sistema operativo enhebra automáticamente las operaciones de IO"? ¿O está diciendo que esto no es un problema en PHP porque PHP crea automáticamente un nuevo hilo para cada solicitud para que una solicitud bloqueada no detenga todo el entorno PHP? (Supongo que esto último ...)
dcow
66
Es lo último.
Joseph
2
espere, si se trata del último, cuáles son las ventajas de no bloquear el I / O PHP (como reactPHP u otra cosa) sobre el bloqueador. todavía
confuso
55
@CharlieParker Sí. La operación asíncrona corre paralela a su código. Pero la devolución de llamada que "vuelve" a los resultados de la operación asincrónica se pone en cola para su ejecución en el código principal cuando el código principal no está ocupado.
Joseph
2
@CharlieParker Aquí hay una publicación que trata más sobre los aspectos internos del mecanismo asíncrono.
Joseph
7
var startTime = new Date().getTime();
var getEndTime = () => {
    var tempEndTime = new Date().getTime();
    var second = (tempEndTime - startTime)/1000
    return `took ${second} sec...to finish\n`
}

console.log('1: start App', getEndTime())
setTimeout(()=>{
    console.log('2: setTimeout', getEndTime())
}, 1000)
console.log('3: End App', getEndTime())

// console -> Process Order:  1 -> 3 -> 2

Ejemplo de código

Wayne Chiu
fuente