Enriquecer los principales comercios de forma concurrente
Requisito
A partir de los totales de gasto por comercio de julio, toma los tres comercios principales y enriquece cada uno con su categoría desde una API (simulada) de directorio de comercios —pero la API limita la tasa de peticiones, así que nunca puede haber más de dos consultas en curso a la vez. Los resultados se imprimen por orden de gasto cuando todas las consultas han terminado, y la consulta falsa cuenta las peticiones que se solapan para que ambas versiones puedan demostrar que el límite se respetó. Los datos están en el código de abajo; ambas versiones deben imprimir las líneas que aparecen bajo Salida esperada.
Salida esperada
Green Grocer — $118.65 (Groceries) Electric Co — $60.34 (Utilities) Noodle Bar — $54.70 (Dining) max lookups in flight: 2
Lado a lado
Dart nativo
FxDart
Por qué difieren
La tarea cambia de naturaleza a mitad de camino —primero una
clasificación síncrona, luego E/S con límite de tasa— y el código de
solo una de las versiones cambia de naturaleza con ella. En FxDart la
costura es un único paso de la cadena: sortBy +
take eligen los comercios, toAsync cruza al
mundo asíncrono, y map + concurrent(2)
ejecutan las consultas de dos en dos, en orden. Dart nativo no tiene
ninguna primitiva para «como mucho dos en curso»:
Future.wait lo dispara todo a la vez, así que la mitad
acotada se convierte en un pool de workers hecho a mano —cursor
compartido, huecos de resultado predimensionados, futures de worker— que
empequeñece la clasificación de dos líneas a la que sirve. Cambiar el
límite, o eliminarlo, es un número en la cadena frente a todo ese
andamiaje.
Benchmark
Caso async: la escala principal es N = 100,000, no 1,000,000. Cada elemento cuesta una vuelta del event loop en ambos lados, así que un millón de awaits reales mediría el event loop de Dart durante minutos — no el pipeline. Los retardos son de longitud cero y se conserva el límite de concurrencia del ejemplo; lo que comparan las barras es la maquinaria del pipeline.
N = 100
Tiempo Empate
Memoria pico Empate
N = 10,000
Tiempo Gana nativo
Memoria pico Empate
N = 100,000
Tiempo Gana nativo
Memoria pico Empate
Las barras son medianas de iteraciones cronometradas repetidas en procesos nuevos por lado (los N pequeños se agrupan por resolución del temporizador). Dos lados a menos del 5% entre sí — o a menos de 0.6 ms, una diferencia que nadie puede percibir — cuentan como empate; las carreras relativas ajustadas se vuelven a medir hasta 5 veces. En una app, cualquier cosa por debajo de unos pocos milisegundos es invisible para el usuario, gane la barra que gane. La memoria es el RSS pico del proceso. La VM de Dart y el dataset son idénticos en ambos lados, así que la diferencia entre las dos barras es lo que retiene el pipeline en sí.