tag script how defer cargar atributo async asynchronous blocking synchronous

asynchronous - script - asíncrono vs sin bloqueo



script defer vs async (12)

¿Cuál es la diferencia entre llamadas asíncronas y no bloqueantes? También entre bloqueo y llamadas síncronas (con ejemplos por favor)?


Al poner esta pregunta en el contexto de NIO y NIO.2 en java 7, async IO es un paso más avanzado que el no bloqueo. Con las llamadas no bloqueadas de NIO de Java, uno configuraría todos los canales (SocketChannel, ServerSocketChannel, FileChannel, etc.) como tal al llamar a AbstractSelectableChannel.configureBlocking(false) . Sin embargo, después de que regresen las llamadas de IO, es probable que aún tenga que controlar las comprobaciones, por ejemplo, cuándo y cuándo volver a leer, escribir, etc.
Por ejemplo,

while (!isDataEnough()) { socketchannel.read(inputBuffer); // do something else and then read again }

Con la API asíncrona en Java 7, estos controles se pueden hacer de una manera más versátil. Una de las 2 formas es usar CompletionHandler . Observe que ambas llamadas de read son no bloqueantes.

asyncsocket.read(inputBuffer, 60, TimeUnit.SECONDS /* 60 secs for timeout */, new CompletionHandler<Integer, Object>() { public void completed(Integer result, Object attachment) {...} public void failed(Throwable e, Object attachment) {...} } }


Como probablemente pueda ver en la multitud de respuestas diferentes (y con frecuencia mutuamente excluyentes), depende de a quién le pregunte. En algunas arenas, los términos son sinónimos. O podrían referirse a dos conceptos similares:

  • Una interpretación es que la llamada hará algo en segundo plano esencialmente sin supervisión para permitir que el programa no se detenga mediante un proceso largo que no es necesario controlar. La reproducción de audio puede ser un ejemplo: un programa podría llamar a una función para reproducir (por ejemplo) un mp3, y desde ese momento podría continuar con otras cosas mientras deja que el sistema operativo administre el proceso de renderización del audio en el hardware de sonido. .
  • La interpretación alternativa es que la llamada hará algo que el programa necesitará monitorear, pero permitirá que la mayor parte del proceso ocurra en segundo plano, solo notificando al programa en puntos críticos del proceso. Por ejemplo, la E / S asíncrona de archivos puede ser un ejemplo: el programa suministra un búfer al sistema operativo para escribir en el archivo, y el sistema operativo solo notifica al programa cuando se completa la operación o se produce un error.

En cualquier caso, la intención es permitir que el programa no se bloquee a la espera de que se complete un proceso lento; la única diferencia real es cómo se espera que el programa responda. Qué término se refiere a lo que también cambia de programador a programador, de lenguaje a lenguaje o de plataforma a plataforma. O los términos pueden referirse a conceptos completamente diferentes (como el uso de síncrono / asíncrono en relación con la programación de hilos).

Lo siento, pero no creo que haya una sola respuesta correcta que sea globalmente cierta.


En muchas circunstancias, son nombres diferentes para la misma cosa, pero en algunos contextos son bastante diferentes. Así que depende. La terminología no se aplica de forma totalmente coherente en toda la industria del software.

Por ejemplo, en la API de sockets clásicos, un socket no bloqueante es uno que simplemente se devuelve de inmediato con un mensaje de error especial "bloquearía", mientras que un socket bloqueador se habría bloqueado. Debe utilizar una función separada, como select o poll para saber cuándo es un buen momento para volver a intentarlo.

Pero los sockets asíncronos (como son compatibles con los sockets de Windows), o el patrón de E / S asíncrono utilizado en .NET, son más convenientes. Llamas a un método para iniciar una operación, y el marco te devuelve la llamada cuando se realiza. Incluso aquí, hay diferencias básicas. Los sockets asincrónicos de Win32 "agrupan" sus resultados en un subproceso de la GUI mediante la transmisión de mensajes de Windows, mientras que .NET IO asíncrono es de subproceso libre (no sabe en qué subproceso se llamará su devolución de llamada).

Así que no siempre significan lo mismo. Para destilar el ejemplo del zócalo, podríamos decir:

  • Bloquear y sincronizar significa lo mismo: usted llama a la API, cuelga el hilo hasta que tiene algún tipo de respuesta y se lo devuelve.
  • No bloquear significa que si una respuesta no puede devolverse rápidamente, la API regresa inmediatamente con un error y no hace nada más. Por lo tanto, debe haber alguna forma relacionada de consultar si la API está lista para ser llamada (es decir, para simular una espera de una manera eficiente, para evitar el sondeo manual en un circuito cerrado).
  • Asíncrono significa que la API siempre se devuelve de inmediato, habiendo iniciado un esfuerzo de "fondo" para cumplir con su solicitud, por lo que debe haber alguna forma relacionada para obtener el resultado.

Los modelos de bloqueo requieren que la aplicación de inicio se bloquee cuando se inicia la E / S. Esto significa que no es posible superponer el procesamiento y la E / S al mismo tiempo. El modelo sin bloqueo sincrónico permite la superposición del procesamiento y la E / S, pero requiere que la aplicación verifique el estado de la E / S de forma recurrente. Esto deja una E / S no bloqueante asíncrona, que permite la superposición del procesamiento y la E / S, incluida la notificación de la finalización de E / S.


Se diferencian solo en la ortografía. No hay diferencia en lo que se refieren. Para ser técnicos se podría decir que difieren en énfasis. El no bloqueo se refiere al flujo de control (no se bloquea). Asíncrono se refiere al momento en que se maneja el evento / datos (no de forma síncrona).


Sin bloqueo: esta función no esperará mientras esté en la pila.

Asíncrono: el trabajo puede continuar en nombre de la llamada a la función después de que esa llamada haya salido de la pila


Una llamada sin bloqueo regresa inmediatamente con los datos disponibles: el número total de bytes solicitados, menos, o ninguno en absoluto.

Una llamada asíncrona solicita una transferencia que se realizará en su totalidad (pero que se completará en algún momento futuro).


síncrono / asíncrono es describir la relación entre dos módulos.
Bloquear / no bloquear es describir la situación de un módulo.

Un ejemplo:
Módulo X: "I".
Módulo Y: "librería".
X pregunta Y: ¿tienes un libro llamado "c ++ primer"?

1) bloqueo: antes de que Y responda a X, X sigue esperando la respuesta. Ahora X (un módulo) está bloqueando. ¿X e Y son dos hilos o dos procesos o un hilo o un proceso? nosotros no sabemos

2) no bloqueante: antes de que Y responda a X, X simplemente se va y hace otras cosas. ¿X puede regresar cada dos minutos para verificar si Y ha terminado su trabajo? ¿O X no regresará hasta que Y lo llame? No lo sabemos Solo sabemos que X puede hacer otras cosas antes de que Y termine su trabajo. Aquí X (un módulo) es no bloqueante. ¿X e Y son dos hilos o dos procesos o un proceso? nosotros no sabemos PERO estamos seguros de que X e Y no pueden ser un hilo.

3) sincrónico: antes de que Y responda a X, X sigue esperando la respuesta. Significa que X no puede continuar hasta que Y termine su trabajo. Ahora decimos: X e Y (dos módulos) son síncronos. ¿X e Y son dos hilos o dos procesos o un hilo o un proceso? nosotros no sabemos

4) asíncrono: antes de que Y responda a X, X sale de allí y X puede hacer otros trabajos. X no regresará hasta que Y lo llame. Ahora decimos: X e Y (dos módulos) son asíncronos. ¿X e Y son dos hilos o dos procesos o un proceso? nosotros no sabemos PERO estamos seguros de que X e Y no pueden ser un hilo.


Por favor, preste atención a las dos oraciones en negrita de arriba. ¿Por qué la oración en negrita en el 2) contiene dos casos mientras que la oración en negrita en el 4) contiene solo un caso? Esta es una clave de la diferencia entre el no bloqueo y el asíncrono.

Aquí hay un ejemplo típico de no bloqueo y síncrono:

// thread X while (true) { msg = recv(Y, NON_BLOCKING_FLAG); if (msg is not empty) { break; } sleep(2000); // 2 sec } // thread Y // prepare the book for X send(X, book);

Puede ver que este diseño no es de bloqueo (se puede decir que la mayoría de las veces este bucle no tiene sentido pero a los ojos de la CPU, X se está ejecutando, lo que significa que X no está bloqueando) mientras que X e Y son sincrónicas porque X puede No continúe haciendo nada (X no puede saltar fuera del bucle) hasta que reciba el libro de Y.
Normalmente, en este caso, el bloqueo X es mucho mejor porque el no bloqueo gasta muchos recursos en un bucle estúpido. Pero este ejemplo es bueno para ayudarlo a comprender el hecho: no bloquear no significa asíncrono.

Las cuatro palabras nos confunden fácilmente, lo que debemos recordar es que las cuatro palabras sirven para el diseño de la arquitectura. Aprender sobre cómo diseñar una buena arquitectura es la única forma de distinguirlos.

Por ejemplo, podemos diseñar este tipo de arquitectura:

// Module X = Module X1 + Module X2 // Module X1 while (true) { msg = recv(many_other_modules, NON_BLOCKING_FLAG); if (msg is not null) { if (msg == "done") { break; } // create a thread to process msg } sleep(2000); // 2 sec } // Module X2 broadcast("I got the book from Y"); // Module Y // prepare the book for X send(X, book);

En el ejemplo aquí, podemos decir que

  • X1 no es bloqueante
  • X1 y X2 son síncronos
  • X e Y son asíncronos

Si lo necesita, también puede describir los hilos creados en X1 con las cuatro palabras.

Las cosas más importantes son: ¿cuándo usamos síncrono en lugar de asíncrono? ¿Cuándo utilizamos el bloqueo en lugar del no bloqueo?

¿Por qué Nginx no bloquea? ¿Por qué está bloqueando Apache?

Para hacer una buena elección, debe analizar su necesidad y probar el rendimiento de diferentes arquitecturas. No existe una arquitectura que sea adecuada para diversas necesidades.


Bloqueo de llamada: el control solo regresa cuando la llamada se completa.

Llamada no bloqueante : el control vuelve inmediatamente. Más tarde, el sistema operativo de alguna manera notifica al proceso que la llamada está completa.

Programa síncrono : un programa que utiliza llamadas de bloqueo . Para no congelarse durante la llamada, debe tener 2 o más subprocesos (por eso se llama Sincrónico: los subprocesos se ejecutan de forma síncrona).

Programa asíncrono : programa que utiliza llamadas no bloqueantes . Puede tener solo 1 hilo y seguir siendo interactivo.


Bloqueo: el control vuelve a invocar el proceso previo después de que se complete el procesamiento de la primitiva (sincronización o asíncrono)

Sin bloqueo: el control vuelve a procesarse inmediatamente después de la invocación


Sincrónico se define como que sucede al mismo tiempo.

Asíncrono se define como que no ocurre al mismo tiempo.

Esto es lo que causa la primera confusión. Sincrónico es en realidad lo que se conoce como paralelo. Si bien asíncrono es secuencial, haz esto, luego hazlo.

Ahora todo el problema se trata de modelar un comportamiento asíncrono, porque tiene alguna operación que necesita la respuesta de otra antes de que pueda comenzar. Por lo tanto, es un problema de coordinación, ¿cómo sabrá que ahora puede iniciar esa operación?

La solución más simple se conoce como bloqueo.

El bloqueo se produce cuando simplemente elige esperar a que se haga otra cosa y le devuelve una respuesta antes de pasar a la operación que lo necesitaba.

Por lo tanto, si necesita poner mantequilla en la tostada y, por lo tanto, primero tiene que tostar a los criados. La forma en que los coordinarías es que primero deberías tostar a los criados, luego mirar fijamente la tostadora hasta que hace estallar la tostada, y luego procedes a ponerles mantequilla.

Es la solución más simple, y funciona muy bien. No hay una razón real para no usarlo, a menos que también tenga otras cosas que necesita hacer que no requieran coordinación con las operaciones. Por ejemplo, haciendo algunos platos. ¿Por qué esperar inactivo mirando el tostador constantemente para que la tostada haga estallar, cuando sabes que tomará un poco de tiempo, y podrías lavar un plato completo mientras termina?

Ahí es donde entran en juego otras dos soluciones conocidas respectivamente como no bloqueantes y asíncronas.

No bloquear es cuando elige hacer otras cosas no relacionadas mientras espera que se realice la operación. Comprobando la disponibilidad de la respuesta como mejor le parezca.

Así que en lugar de mirar la tostadora para que salte. Vas a lavar un plato entero. Y luego echas un vistazo a la tostadora para ver si las tostadas se han reventado. Si no lo han hecho, vas a lavar otro plato, revisando la tostadora entre cada plato. Cuando ves que las tostadas se han reventado, dejas de lavar los platos y, en cambio, tomas la tostada y te pones mantequilla.

Sin embargo, tener que revisar constantemente los brindis puede ser molesto, imagina que la tostadora está en otra habitación. Entre platos, pierdes el tiempo yendo a esa otra habitación para ver el brindis.

Aquí viene asíncrono.

Asíncrono es cuando elige hacer otras cosas no relacionadas mientras espera que se realice la operación. Sin embargo, en lugar de verificarlo, delegue el trabajo de verificarlo en otra cosa, podría ser la operación en sí misma o un observador, y debe notificarlo y posiblemente interrumpirlo cuando la respuesta esté disponible para que pueda continuar con la otra operación que lo necesitaba.

Es una terminología extraña. No tiene mucho sentido, ya que todas estas soluciones son formas de crear una coordinación asíncrona de tareas dependientes. Por eso prefiero llamarlo evented.

Así que para este, usted decide actualizar su tostadora para que suene cuando terminen los brindis. Sucede que estás escuchando constantemente, incluso mientras estás lavando platos. Al escuchar el pitido, hace cola en su memoria para que, tan pronto como haya terminado de lavar su plato actual, se detenga y ponga la mantequilla sobre la tostada. O puede optar por interrumpir el lavado del plato actual y tratar el brindis de inmediato.

Si tiene problemas para escuchar el pitido, puede pedirle a su compañero que vea la tostadora por usted, y que venga a avisarle cuando esté lista. Su compañero puede elegir cualquiera de las tres estrategias anteriores para coordinar su tarea de vigilar la tostadora y decirle cuándo están listas.

En una nota final, es bueno entender que mientras que el no bloqueo y el asíncrono (o lo que prefiero llamar evented) le permiten hacer otras cosas mientras espera, no tiene demasiado. Puede elegir realizar un bucle constante para verificar el estado de una llamada sin bloqueo, sin hacer nada más. Sin embargo, eso es a menudo peor que el bloqueo (como mirar el tostador, luego alejarlo y luego volver a utilizarlo hasta que esté listo), por lo que muchas API sin bloqueo le permiten pasar al modo de bloqueo. Para eventos, solo puede esperar inactivo hasta que se le notifique. La desventaja en ese caso es que, para empezar, agregar la notificación fue complejo y potencialmente costoso. Tuvo que comprar una tostadora nueva con la función de pitido o convencer a su compañero para que la cuide por usted.

Y una cosa más, es necesario realizar las concesiones que los tres proporcionan. Uno no es obviamente mejor que los otros. Piensa en mi ejemplo. Si su tostadora es tan rápida, no tendrá tiempo para lavar un plato, ni siquiera comenzará a lavarlo, así de rápida será su tostadora. Comenzar con algo más en ese caso es solo una pérdida de tiempo y esfuerzo. El bloqueo servirá. Del mismo modo, si lavar un plato durará 10 veces más que el tostado. Tienes que preguntarte qué es lo más importante para hacer? La tostada puede estar fría y dura en ese momento, no vale la pena, el bloqueo también servirá. O deberías elegir cosas más rápidas para hacer mientras esperas. Hay más, obviamente, pero mi respuesta ya es bastante larga, mi punto es que debes pensar en todo eso y en la complejidad de implementar cada uno para decidir si vale la pena, y si realmente mejorará tu rendimiento o rendimiento.

Editar:

Aunque esto ya es largo, también quiero que esté completo, así que agregaré dos puntos más.

1) También existe comúnmente un cuarto modelo conocido como multiplexado . Esto ocurre cuando mientras espera una tarea, comienza otra, y mientras espera ambas, inicia una más, y así sucesivamente, hasta que tiene muchas tareas iniciadas y luego, espera inactiva, pero en general ellos. Entonces, tan pronto como se haga cualquiera, puede continuar con el manejo de su respuesta y luego volver a esperar a los demás. Se conoce como multiplexado, porque mientras espera, debe revisar cada tarea una tras otra para ver si se han completado, ad vitam, hasta que se complete una. Es un poco una extensión por encima del bloqueo normal.

En nuestro ejemplo, sería como encender la tostadora, luego el lavaplatos, luego el microondas, etc. Y luego esperar en cualquiera de ellos. Donde verificas la tostadora para ver si está listo, si no, revisas el lavaplatos, si no, el microondas y vuelven a funcionar.

2) Aunque creo que es un gran error, a menudo se usa sincrónico para significar una cosa a la vez. Y asíncronas muchas cosas a la vez. Por lo tanto, verá el bloqueo sincrónico y el no bloqueo que se utiliza para referirse al bloqueo y al no bloqueo. Y el bloqueo asíncrono y el no bloqueo se utilizan para referirse a multiplexados y con eventos.

Realmente no entiendo cómo llegamos allí. Pero cuando se trata de IO y Computación, síncrono y asíncrono a menudo se refiere a lo que se conoce mejor como no superpuesto y superpuesto. Es decir, asíncrono significa que IO y la computación se superponen, es decir, que suceden simultáneamente. Mientras que sincrónica significa que no lo son, así suceden secuencialmente. Para el bloqueo sincrónico sincrónico, eso significaría que no inicia otro IO o Computación, simplemente está ocupado esperando y simulando una llamada de bloqueo. Ojalá la gente dejara de usar de forma sincrónica y asíncrona de esa manera. Así que no lo estoy alentando.


  • Asíncrono se refiere a algo hecho en paralelo , por ejemplo, es otro hilo.
  • El no bloqueo a menudo se refiere al sondeo , es decir, verificar si se cumple una condición determinada (el socket es legible, el dispositivo tiene más datos, etc.)