Diseñado para desarrolladores en la intersección de la curiosidad y el crecimiento profesional, este primer objetivo es iluminar cómo la programación asíncrona puede elevar el rendimiento, la escalabilidad y la capacidad de respuesta de las aplicaciones. Al centrarnos en los principios universales de las operaciones sin bloquear y los circuitos de eventos, nos aventuramos más allá de tecnologías específicas como AsyncIO, Node.js o Go.
Esta exploración está diseñada para los desarrolladores de software ansiosos por comprender las eficiencias que impulsan el software moderno sin la complejidad del jargón técnico.
Piense en cómo una única solicitud de tratamiento de pedidos es como una carretera de una sola línea en una ciudad ocupada: cada solicitud es un coche, y cuando solo hay una pista, los coches se alinean, causando retrasos.Pero qué pasa si nuestra ciudad - nuestro servicio - podía gestionar el tráfico de manera más inteligente?Es donde entra en juego la magia de un tiempo de ejecución asíncrono.Es como agregar un sistema de tráfico inteligente a nuestra ciudad, guiando los coches a través de varias pistas y intersecciones sin esperar.
Este sistema mantiene el tráfico fluyendo sin problemas, asegurando que ningún coche (o tarea) espera demasiado, lo que es exactamente cómo un tiempo de ejecución asíncrono mantiene nuestro software funcionando de manera eficiente.
Vamos a considerar un ejemplo de un servicio que completa las operaciones de I/O de forma sincronizada.Para la claridad, estas operaciones se muestran fuera del flujo principal de ejecución en el diagrama:
El bloqueo de I/O durante la fase de inicio de su servicio puede ser aceptable, pero es aconsejable evitar este enfoque al procesar solicitudes externas.El siguiente diagrama ilustra cómo se puede mejorar la eficiencia del servicio mediante la adopción de operaciones de I/O no bloqueantes:
Estos ejemplos resaltan escenarios en los que se maximizan las ganancias de rendimiento del servidor. sin embargo, la ventaja de las operaciones no bloqueantes persiste a través de cualquier frecuencia de solicitudes entrantes.
El tiempo total necesario para procesar una solicitud (desde la solicitud inicial del cliente a la respuesta final, como se representa por el número azul a la derecha) se reducirá invariablemente, siempre que haya suficientes cables para procesar todas las solicitudes.
Entonces nos encontramos con una práctica que puede parecer contraintuitiva para muchos desarrolladores.Cuando las operaciones de I/O constituyen una parte significativa del tiempo de procesamiento de solicitudes, optimizar otros segmentos de código puede producir una ligera mejora.La duración para recuperar datos de una caché podría alinearse estrechamente con el tiempo dedicado a la lógica empresarial y el rendimiento de plantillas.
El empleo de la caché o una base de datos en proceso puede reducir los tiempos de recuperación de datos en comparación con otras actividades de procesamiento.
Para segmentar el código de manera efectiva y facilitar la ejecución de llamadas, se puede instruir al tiempo de ejecución para proceder al siguiente ciclo de loop de eventos.A continuación se muestra un ejemplo ilustrativo de cómo se aplica este concepto:
// bloquear callbacks función func1_cb(str, cb) { var res = func1(str); cb(res); } función func2_cb(str, cb) { var res = func2(str); cb(res); } // no bloquear callbacks función func1_cb(str, cb) { var res = func1(str); } función func2_cb(str, cb) { var res = func2(str); } // proceso.nextick(función () { cb(res); }; } // uso ejemplo función func1_cb(content, función (str) función {2_cb(str, función (resultado // trabajo con resultado } }); }
// blocking callbacks
function func1_cb(str, cb) {
var res = func1(str);
cb(res);
}
function func2_cb(str, cb) {
var res = func2(str);
cb(res);
}
// non-blocking callbacks
function func1_cb(str, cb) {
var res = func1(str);
process.nextTick(function () {
cb(res);
});
}
function func2_cb(str, cb) {
var res = func2(str);
process.nextTick(function () {
cb(res);
});
}
// usage example
func1_cb(content, function (str) {
func2_cb(str, function (result) {
// work with result
});
});
Al adoptar esta metodología para dividir dos partes de cálculos, el tiempo total de procesamiento para escenarios con llegadas de solicitudes casi simultáneas permanece el mismo.
Este escenario representa el resultado menos favorable cuando se emplea la estrategia de «next tick». Como se muestra en el ejemplo inicial, el método de «next tick» resulta benigno para solicitudes raras. Si las solicitudes llegan a un ritmo moderado, aprovechar esta técnica aumenta la velocidad de procesamiento al permitir que la iniciación de nuevas solicitudes y el inicio de operaciones no bloqueantes se interrumpan durante las pausas de ejecución. Este enfoque reduce efectivamente tanto el tiempo total de procesamiento como el tiempo medio por solicitud:
En conclusión, la adopción de I/O sin bloqueo es crucial para mejorar el rendimiento de las aplicaciones y beneficiosa en entornos con volúmenes de solicitudes entrantes escasos y pesados.Además, la secuenciación efectiva del flujo de ejecución - ilustrada por conceptos similares a la técnica de "next tick" - mejora significativamente la eficiencia del servidor.