¿Cuál es la diferencia entre llamadas asíncronas y no bloqueantes? ¿También entre bloqueo y llamadas sincrónicas (con ejemplos, por favor)?
¿Cuál es la diferencia entre llamadas asíncronas y no bloqueantes? ¿También entre bloqueo y llamadas sincrónicas (con ejemplos, por favor)?
Respuestas:
En muchas circunstancias, son nombres diferentes para la misma cosa, pero en algunos contextos son bastante diferentes. Entonces eso depende. La terminología no se aplica de manera totalmente coherente en toda la industria del software.
Por ejemplo, en la clásica API de sockets, un socket sin bloqueo es uno que simplemente regresa inmediatamente con un mensaje de error especial "bloquearía", mientras que un socket de bloqueo se habría bloqueado. Tiene que usar una función separada como select
o poll
para averiguar cuándo es un buen momento para volver a intentarlo.
Pero los zócalos asíncronos (como lo admiten los zócalos de Windows), o el patrón de E / S asíncrono utilizado en .NET, son más convenientes. Llama a un método para iniciar una operación, y el marco le devuelve la llamada cuando termina. Incluso aquí, hay diferencias básicas. Los sockets asíncronos Win32 "reúnen" sus resultados en un subproceso de GUI específico al pasar mensajes de Windows, mientras que .NET asincrónico IO es de subproceso libre (no sabe en qué subproceso se llamará a su devolución de llamada).
Entonces no siempre significan lo mismo. Para destilar el ejemplo del zócalo, podríamos decir:
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 a Y: ¿tienes un libro llamado "c ++ primer"?
1) bloqueo: antes de que Y responda X, X sigue esperando allí la respuesta. Ahora X (un módulo) está bloqueando. X e Y son dos hilos o dos procesos o un hilo o un proceso? No lo sabemos
2) sin bloqueo: antes de que Y responda X, X simplemente se va de allí y hace otras cosas. ¿X puede regresar cada dos minutos para verificar si Y ha terminado su trabajo? ¿O X no volverá 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) no es bloqueante. X e Y son dos hilos o dos procesos o un proceso? No lo sabemos PERO estamos seguros de que X e Y no podrían ser un hilo.
3) síncrono: antes de que Y responda a X, X sigue esperando allí la respuesta. Significa que X no puede continuar hasta que Y termine su trabajo. Ahora decimos: X e Y (dos módulos) son sincrónicos. X e Y son dos hilos o dos procesos o un hilo o un proceso? No lo sabemos
4) asíncrono: antes de que Y responda X, X se va de allí y X puede hacer otros trabajos. X no volverá 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? No lo sabemos PERO estamos seguros de que X e Y no podrían ser un hilo.
Por favor, preste atención a las dos oraciones en negrita anteriores. ¿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 no bloqueo y asíncrono.
Aquí hay un ejemplo típico sobre sin bloqueo y sincrónico:
// 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 bloquea (puede decir que la mayoría de las veces este bucle hace algo sin sentido, pero a los ojos de la CPU, X se está ejecutando, lo que significa que X no bloquea) mientras que X e Y están sincronizados porque X puede No continúe haciendo ninguna otra cosa (X no puede salirse del bucle) hasta que obtenga el libro de Y.
Normalmente, en este caso, hacer que el bloqueo X sea mucho mejor porque el no bloqueo gasta muchos recursos para un bucle estúpido. Pero este ejemplo es bueno para ayudarlo a comprender el hecho: no bloquear no significa asincrónico.
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 a 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
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 usamos bloqueo en lugar de 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.
Poniendo 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 sin bloqueo de Java NIO, uno establecería todos los canales (SocketChannel, ServerSocketChannel, FileChannel, etc.) como tales llamando AbstractSelectableChannel.configureBlocking(false)
. Sin embargo, después de que esas llamadas IO regresen, es probable que aún necesite controlar las comprobaciones, como si leer y escribir nuevamente, etc.,
por ejemplo,
while (!isDataEnough()) {
socketchannel.read(inputBuffer);
// do something else and then read again
}
Con la API asincrónica en Java 7, estos controles se pueden realizar de formas más versátiles. Una de las 2 formas es usar CompletionHandler
. Tenga en cuenta que ambas read
llamadas no son de bloqueo.
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) {...}
}
}
FileChannel
no se puede seleccionar y no se puede configurar para que no se bloquee.
Como probablemente pueda ver en la multitud de respuestas diferentes (y a menudo mutuamente excluyentes), depende de a quién le pregunte. En algunos ámbitos, los términos son sinónimos. O podrían referirse a dos conceptos similares:
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 forma en que se espera que responda el programa es la única diferencia real. El término se refiere al 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 subprocesos).
Lo siento, pero no creo que haya una sola respuesta correcta que sea globalmente cierta.
Una llamada sin bloqueo regresa inmediatamente con los datos disponibles: el número total de bytes solicitados, menos o ninguno.
Una llamada asincrónica solicita una transferencia que se realizará en su totalidad (en su totalidad) pero que se completará en algún momento futuro.
Sin bloqueo: esta función no esperará mientras esté en la pila.
Asíncrono: el trabajo puede continuar en nombre de la llamada de función después de que esa llamada haya abandonado la pila
Sincrónico se define como sucediendo al mismo tiempo.
Asíncrono se define como no sucediendo al mismo tiempo.
Esto es lo que causa la primera confusión. Sincrónico es en realidad lo que se conoce como paralelo. Mientras asíncrono es secuencial, haga esto, luego haga eso.
Ahora todo el problema se trata de modelar un comportamiento asincrónico, porque tienes 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 comenzar esa operación?
La solución más simple se conoce como bloqueo.
El bloqueo es cuando simplemente elige esperar a que se haga lo otro y devolverle una respuesta antes de pasar a la operación que lo necesitaba.
Entonces, si necesita poner mantequilla en una tostada y, por lo tanto, primero debe tostarla. La forma en que los coordinarías es que primero tostarías la raza, luego mirarías sin parar la tostadora hasta que esta brille, y luego procederías 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 tenga otras cosas que deba hacer que no requieran coordinación con las operaciones. Por ejemplo, lavando algunos platos. ¿Por qué esperar sin hacer nada mirando la tostadora constantemente para que la tostada explote, cuando sabes que tomará un poco de tiempo y podrías lavar un plato entero mientras termina?
Ahí es donde entran en juego otras dos soluciones conocidas respectivamente como no bloqueantes y asincrónicas.
Sin bloqueo es cuando elige hacer otras cosas no relacionadas mientras espera que se realice la operación. Verificando la disponibilidad de la respuesta como mejor le parezca.
Entonces, en lugar de mirar la tostadora para que explote. Ve y lava un plato entero. Y luego miras la tostadora para ver si las tostadas han aparecido. Si no lo han hecho, ve 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 las tostadas y pasas a ponerles mantequilla.
Sin embargo, tener que revisar constantemente las tostadas 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 las tostadas.
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, delega el trabajo de verificar a otra cosa, podría ser la operación en sí misma o un observador, y tiene esa cosa notificando y posiblemente interrumpe cuando la respuesta está disponible para que pueda proceder a 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 asincrónica de tareas dependientes. Por eso prefiero llamarlo evented.
Entonces, para este, decides actualizar tu tostadora para que suene cuando las tostadas estén listas. Usted está escuchando constantemente, incluso mientras lava los platos. Al escuchar el pitido, hace cola en su memoria que tan pronto como termine de lavar su plato actual, se detendrá e irá a poner la mantequilla en la tostada. O puede optar por interrumpir el lavado del plato actual y lidiar con la tostada de inmediato.
Si tiene problemas para escuchar el pitido, puede pedirle a su compañero que vigile la tostadora por usted y que le avise cuando la tostada esté lista. Su compañero puede elegir cualquiera de las tres estrategias anteriores para coordinar su tarea de observar la tostadora y decirle cuándo están listas.
En una nota final, es bueno entender que si bien el bloqueo y la sincronización (o lo que prefiero llamar igualado) te permiten hacer otras cosas mientras esperas, no tienes que hacerlo. Puede elegir realizar un bucle constante para verificar el estado de una llamada sin bloqueo, sin hacer nada más. Sin embargo, eso a menudo es peor que bloquear (como mirar la tostadora, luego alejarla y luego volver a mirarla hasta que esté lista), por lo que muchas API sin bloqueo le permiten pasar del modo de bloqueo. Para Evented, puede esperar inactivo hasta que se le notifique. La desventaja en ese caso es que agregar la notificación fue complejo y potencialmente costoso para empezar. Tuviste que comprar una nueva tostadora con función de pitido, o convencer a tu pareja para que la vea por ti.
Y una cosa más, debe darse cuenta de las compensaciones que proporcionan los tres. Uno no es obviamente mejor que los demás. Piensa en mi ejemplo. Si su tostadora es tan rápida, no tendrá tiempo de lavar un plato, ni siquiera comenzará a lavarlo, así de rápido es 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 tomará 10 veces más tiempo que el tostado. Tienes que preguntarte qué es más importante para hacer. El brindis podría enfriarse y endurecerse para entonces, no vale la pena, el bloqueo también lo hará. O deberías elegir cosas más rápidas para hacer mientras esperas. Obviamente, hay más, pero mi respuesta ya es bastante larga, mi punto es que debes pensar en todo eso y en las complejidades de implementar cada uno para decidir si vale la pena, y si es así '
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 es cuando mientras espera una tarea, inicia otra, y mientras espera ambas, comienza una más, y así sucesivamente, hasta que haya comenzado muchas tareas y luego, espere inactivo, pero en todos ellos. Por lo tanto, tan pronto como haya terminado, 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 verificar cada tarea una después de la otra para ver si están terminadas, ad vitam, hasta que una esté terminada. Es una extensión un poco superior a la normal sin bloqueo.
En nuestro ejemplo, sería como encender la tostadora, luego el lavaplatos, luego el microondas, etc. Y luego esperar en cualquiera de ellos. Donde verificaría la tostadora para ver si está lista, si no, verificaría el lavavajillas, si no, el microondas y todo de nuevo.
2) Aunque creo que es un gran error, sincrónico a menudo se usa para significar una cosa a la vez. Y muchas cosas asíncronas a la vez. Por lo tanto, verá el bloqueo sincrónico y el no bloqueo utilizados para referirse al bloqueo y al no bloqueo. Y el bloqueo asincrónico y el no bloqueo solían referirse a multiplexado e igualado.
Realmente no entiendo cómo llegamos allí. Pero cuando se trata de E / S y Computación, síncrono y asíncrono a menudo se refieren a lo que se conoce mejor como no superpuesto y superpuesto. Es decir, asíncrono significa que IO y Computación se superponen, es decir, que suceden simultáneamente. Si bien sincrónico significa que no lo son, suceden de manera secuencial. Para el bloqueo sincrónico, eso significaría que no inicia otro IO o Computación, solo está ocupado esperando y simulando una llamada de bloqueo. Desearía que la gente dejara de usar mal sincrónicamente y de forma asincrónica. Entonces no lo estoy alentando.
Bloqueo de llamadas: el control regresa solo cuando se completa la llamada.
Llamada sin bloqueo : el control regresa de inmediato. El sistema operativo posterior de alguna manera notifica al proceso que la llamada se ha completado.
Programa sincrónico : un programa que utiliza llamadas de bloqueo . Para no congelarse durante la llamada, debe tener 2 o más subprocesos (es por eso que se llama Sincrónico: los subprocesos se ejecutan sincrónicamente).
Programa asincrónico : un programa que utiliza llamadas sin bloqueo . Puede tener solo 1 hilo y seguir siendo interactivo.
Difieren solo en ortografía. No hay diferencia en lo que se refieren. Para ser técnico, se podría decir que difieren en énfasis. Sin bloqueo se refiere al flujo de control (no se bloquea). Asíncrono se refiere a cuándo se maneja el evento \ datos (no sincrónicamente).
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 las E / S al mismo tiempo. El modelo síncrono sin bloqueo permite la superposición de procesamiento y E / S, pero requiere que la aplicación verifique el estado de la E / S de forma recurrente. Esto deja una E / S asincrónica sin bloqueo, que permite la superposición de procesamiento y E / S, incluida la notificación de la finalización de E / S.
Bloqueo: el control vuelve a invocar el preceso después de que se completa el procesamiento de la primitiva (sincronización o asíncrona)
Sin bloqueo: el control vuelve a procesarse inmediatamente después de la invocación