Obtener de 4 en 4, resultados en orden
Requisito
Obtén ocho perfiles de usuario cuyos tiempos de respuesta difieren, manteniendo como mucho 4 peticiones en vuelo a la vez — e imprime los resultados en orden de origen (el usuario 1 primero), más el máximo de peticiones en vuelo observado como prueba del límite. Los retardos están en el código; las dos versiones deben imprimir las líneas que aparecen bajo Salida esperada.
Salida esperada
user#1 user#2 user#3 user#4 user#5 user#6 user#7 user#8 max in flight: 4
Lado a lado
RxDart
FxDart
Por qué difieren
Ambos lados acotan la concurrencia en un operador, y el contador
compartido muestra que ambos alcanzan de verdad 4 en vuelo. La
división es por el orden.
flatMap(maxConcurrent: 4) es una fusión: emite cada
resultado interno en el momento en que se completa, así que con estos
retardos el usuario 7 (10 ms) se imprimiría antes que el usuario
1 (80 ms). Para cumplir el requisito el lado RxDart etiqueta
cada resultado con su id, lo recoge todo y ordena al final — el orden
que tenía la fuente lo destruye la fusión y hay que reconstruirlo a
mano al terminar.
mapConcurrent(4, fetch) nunca pierde el orden en primer
lugar. En un pipeline pull, la concurrencia es una propiedad de la
demanda, no de la entrega: el operador lanza cuatro pulls
solapados pero entrega los resultados aguas abajo en el orden en que
se pidieron, reteniendo una llegada rápida y tardía hasta que sus
predecesoras más lentas hayan salido. Acotado-y-ordenado es la forma
que la mayoría del trabajo por lotes realmente quiere — resultados
alineados con las entradas, límites de tasa respetados — y aquí es el
comportamiento por defecto en lugar de una reconstrucción. Cuando el
orden de terminación es lo que de verdad quieres, eso también existe
— concurrentPool, el siguiente ejemplo — pero es la
variante que eliges, no el comportamiento que deshaces.
Benchmark
Caso async: la escala principal es N = 10,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 FxDart
Memoria pico Gana FxDart
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í.