programming languages - ¿Cuál es la diferencia entre: arquitecturas asincrónicas, sin bloqueo, Event-Base?
programming-languages asynchronous (5)
Cuál es la diferencia entre:
- Asincrónico ,
- Sin bloqueo , y
- Arquitecturas de base de eventos ?
¿Puede algo ser asincrónico y no bloqueante (y basado en eventos )?
¿Qué es más importante en la programación, tener algo: asíncrono, no bloqueante y / o base de eventos (o los 3)?
Si pudieras dar ejemplos, sería genial.
Esta pregunta se realiza porque estaba leyendo este excelente artículo de StackOverflow sobre un tema similar, pero no responde a mis preguntas anteriores.
En general, una arquitectura sin bloqueo se basa en llamadas a métodos que, aunque pueden ejecutarse durante mucho tiempo en el hilo del trabajador , no bloquean el hilo de llamada . Si el hilo de llamada necesita adquirir información sobre o desde la tarea que está ejecutando el hilo de trabajo, depende de la secuencia de llamada hacer eso.
Una arquitectura basada en eventos se basa en el concepto de código que se ejecuta en respuesta a eventos que se disparan. El momento de la ejecución del código generalmente no es determinista, pero los eventos pueden invocar métodos de bloqueo; El hecho de que un sistema esté basado en eventos no significa que todo lo que hace no sea de bloqueo.
En general, una arquitectura asíncrona es una arquitectura basada en eventos y sin bloqueo.
Cuando se realiza una llamada asíncrona, los manejadores de eventos se registran con la API proporcionando servicios de sincronización, para notificar a la persona que llama que ha sucedido lo que le interesa a la persona que llama. La llamada vuelve inmediatamente (comportamiento no bloqueante) y la persona que llama puede continuar la ejecución. Cuando los eventos se activan en el proceso de llamada, se manejarán en algún subproceso de ese proceso.
Es importante entender si los eventos se manejarán en el mismo subproceso o no, ya que esto afectará la naturaleza no bloqueante de la ejecución, pero no conozco personalmente ninguna biblioteca que ejecute la gestión de ejecución asincrónica en un solo subproceso.
Eliminé el párrafo anterior porque no es estrictamente correcto, como se dijo. Mi intención era decir que aunque las operaciones en el sistema no son de bloqueo, como realizar llamadas a una instalación de SO y continuar la ejecución, la naturaleza de la ejecución de un solo subproceso significa que cuando se desencadenan los eventos, estarán compitiendo con otras tareas de procesamiento para calcular el tiempo en el hilo.
En un hardware asincrónico, el código le pide a alguna entidad que haga algo y es libre de hacer otras cosas mientras se realiza la acción; una vez que se completa la acción, la entidad típicamente señalizará el código de alguna manera. Una arquitectura no bloqueante tomará nota de acciones de ocurrencia espontánea en las que el código podría estar interesado, y permitirá que el código pregunte qué acciones se han producido, pero el código solo tendrá conocimiento de tales acciones cuando pregunte explícitamente sobre ellas. Una arquitectura basada en eventos notificará afirmativamente el código cuando ocurran eventos espontáneamente.
Considere un puerto serie, desde el cual el código querrá recibir 1,000 bytes.
En una arquitectura de lectura de bloqueo, el código esperará hasta que hayan llegado 1.000 bytes o decida abandonar.
En una arquitectura de lectura asincrónica, el código le dirá al controlador que quiere 1,000 bytes, y se le notificará cuando hayan llegado 1000 bytes.
En una arquitectura sin bloqueo, el código puede preguntar en cualquier momento cuántos bytes han llegado, y puede leer cualquiera o todos esos datos cuando lo considere oportuno, pero la única forma en que puede saber cuándo han llegado todos los datos es preguntar; si el código quiere saber dentro de un cuarto de segundo cuando ha llegado el 1000o byte, debe verificar cada cuarto de segundo aproximadamente.
En una arquitectura basada en eventos, el controlador del puerto serie notificará a la aplicación cada vez que lleguen datos. El controlador no sabrá cuántos bytes desea la aplicación, por lo que la aplicación debe ser capaz de gestionar las notificaciones para cantidades menores o mayores que las que desea la aplicación.
Para mí, no bloquear significa que la ejecución de una acción en un hilo no depende de la ejecución de otros hilos, en particular no requiere una sección crítica.
Asíncrono significa que la ejecución ocurre fuera del flujo de la persona que llama, y es potencialmente diferida. La ejecución normalmente ocurre en otro hilo.
Leer datos concurrentes es no bloqueante (no es necesario bloquearlo), pero sincrónico. Por el contrario, la escritura simultánea de datos de forma síncrona es de bloqueo (requiere un bloqueo exclusivo). Una forma de hacerlo no bloqueante desde la perspectiva del flujo principal es hacer que las escrituras sean asíncronas y diferir su ejecución.
El concepto de evento es otra cosa, lo que en términos generales significa que estás informado cuando ocurre algo. Si las escrituras se han ejecutado de forma asincrónica, se puede generar un evento para informar a otras partes del sistema una vez que se haya ejecutado la escritura. Las otras partes responderán al evento. El sistema puede construirse únicamente sobre eventos como la única forma de comunicarse entre componentes (piense en el modelo de actor), pero no debe ser necesariamente el caso.
Los tres términos están relacionados, pero son conceptos diferentes para mí. Sin embargo, puede ser que la gente los use de una manera intercambiable.
Asíncrono asíncrono significa literalmente no síncrono. El correo electrónico es asincrónico. Usted envía un correo, no espera obtener una respuesta AHORA. Pero no es sin bloqueo. Básicamente, lo que significa es una arquitectura donde los "componentes" se envían mensajes entre sí sin esperar una respuesta inmediata. Las solicitudes HTTP son sincrónicas. Envía una solicitud y obtén una respuesta.
Sin bloqueo Este término se usa principalmente con IO. Lo que esto significa es que cuando realiza una llamada al sistema, regresará inmediatamente con cualquier resultado que tenga sin poner su cadena de trabajo en modo de suspensión (con alta probabilidad). Por ejemplo, las llamadas de lectura / escritura sin bloqueo regresan con lo que sea que puedan hacer y esperan que la persona que llama ejecute de nuevo la llamada. try_lock, por ejemplo, es una llamada no bloqueante. Se bloqueará solo si se puede adquirir el bloqueo. La semántica habitual para las llamadas a los sistemas es bloqueante. read esperará hasta que tenga algunos datos y pondrá hilo de llamada en suspensión.
Base de eventos Este término proviene de libevent. las llamadas de lectura / escritura sin bloqueo en sí mismas son inútiles porque no le dicen "cuándo" debe devolverlas (vuelva a intentarlo). select / epoll / IOCompletionPort, etc. son diferentes mecanismos para descubrir desde el sistema operativo "cuándo" se espera que estas llamadas devuelvan datos "interesantes". libevent y otras bibliotecas de este tipo proporcionan envoltorios sobre estas instalaciones de supervisión de eventos proporcionadas por diversos SO y proporcionan una API consistente para trabajar con la que se ejecuta en todos los sistemas operativos. IO sin bloqueo va de la mano con Event-base.
Creo que estos términos se superponen. Por ejemplo, el protocolo HTTP es sincrónico, pero la implementación de HTTP que utiliza IO sin bloqueo puede ser asíncrona. Nuevamente, una llamada API sin bloqueo como read / write / try_lock es síncrona (inmediatamente da una respuesta) pero el "manejo de datos" es asincrónico.
Entonces, para responder a su primera y segunda pregunta:
El no bloqueo es, de hecho, el mismo que el asincrónico: realiza la llamada y obtendrá un resultado más adelante, pero mientras eso ocurre, puede hacer otra cosa. El bloqueo es lo opuesto. Espera a que regrese la llamada antes de continuar su viaje.
Ahora el código Async / Non-blocking suena absolutamente fantástico, y lo es. Pero tengo palabras de advertencia. Async / Non-blocking son excelentes cuando se trabaja en entornos restringidos, como en un teléfono móvil ... tenga en cuenta la CPU / memoria limitada. También es bueno para el desarrollo del front-end, donde su código necesita reaccionar de algún modo a un widget UI.
Async es fundamental para la forma en que deben funcionar todos los sistemas operativos: te hacen cositas en el fondo y activan tu código cuando han hecho lo que pedías, y cuando esa llamada falla, te dicen que no lo hizo funciona ya sea por una excepción, o algún tipo de código de retorno / objeto de error.
En el momento en que su código solicita algo que demorará un poco en responder, su sistema operativo sabe que puede estar ocupado haciendo otras cosas. Su código - un proceso, hilo o equivalente, bloquea. Su código es totalmente ajeno a qué más está sucediendo en el sistema operativo mientras espera que se realice esa conexión de red, o mientras espera esa respuesta de una solicitud HTTP, o mientras espera que se lea / escriba un archivo, y pronto. Su código podría "simplemente" estar esperando un clic del mouse. Lo que sucedía realmente en ese momento era que su sistema operativo administraba, programaba y reaccionaba sin inconvenientes a los "eventos", cosas que el sistema operativo busca, como administrar la memoria, E / S (teclado, mouse, disco, Internet), otras tareas, recuperación de fallas, etc.
Los sistemas operativos son frikin ''hard-core. Son realmente buenos ocultando todas las cosas complicadas de bloqueo / no bloqueo de parte del programador. Y así es como la mayoría de los programadores llegaron a donde estamos hoy con el software. Ahora que estamos alcanzando los límites de la CPU, la gente dice que se pueden hacer cosas en paralelo para mejorar el rendimiento. Esto significa que Async / no-bloqueo parece algo muy favorable que hacer, y sí, si su software lo exige, puedo estar de acuerdo.
Si está escribiendo un servidor web back-end, proceda con precaución. Recuerde que puede escalar horizontalmente por mucho más barato. Sin embargo, Netflix / Amazon / Google / Facebook son excepciones obvias a esta regla, simplemente porque les resulta menos costoso usar menos hardware.
Te diré por qué el código async / non-blocking es una pesadilla con los sistemas back-end ....
1) Se convierte en una denegación de servicio en la productividad ... tienes que pensar MUCHO más, y cometes muchos errores en el camino.
2) Las huellas de pila en el código reactivo se vuelven indescifrables; es difícil saber qué llamó qué, cuándo, por qué y cómo. Buena suerte con la depuración.
3) Debes pensar más acerca de cómo fallan las cosas, especialmente cuando muchas cosas vuelven a estar fuera de orden de cómo las enviaste. En el viejo mundo, hiciste una cosa a la vez.
4) Es más difícil de probar.
5) Es más difícil de mantener.
6) Es doloroso. La programación debe ser una alegría y diversión. Solo a los masoquistas les gusta el dolor. Las personas que escriben marcos concurrentes / reactivos son sádicos.
Y sí, he escrito sincronización y asincronización. Prefiero síncrona ya que 99.99 de las aplicaciones de back-end pueden funcionar con este paradigma. Las aplicaciones de front-end necesitan código reactivo, sin dudas, y ese siempre ha sido el camino.
Sí, el código puede ser asíncrono, no bloqueante Y basado en eventos.
Lo más importante en la programación es asegurarse de que su código funcione y responda en un tiempo aceptable. Mantente en ese principio clave y no puedes equivocarte.