Importación por lotes con límite de tasa

Gana FxDart async

Requisito

Envía nueve transacciones del libro de cuentas (están en el código de abajo) a un endpoint de importación que acepta lotes de tres, una llamada cada vez: estrictamente secuencial, nunca solapadas. Después de cada lote, registra su tamaño, su importe y el total acumulado importado hasta el momento; imprime los resúmenes de lote en orden y luego demuestra que se respetó el límite de tasa mediante el contador de máximo en vuelo (debe marcar 1).

En FxDart la política entera es la cadena: chunk(3) fija el tamaño del lote, concurrent(1) fija el ritmo y scan hila el total acumulado a través de las confirmaciones (drop(1) descarta el valor inicial del scan). El propio endpoint simula la latencia con delay y suma su lote con sumBy.

Salida esperada
importing 9 txns in batches of 3, one at a time:
  batch 1: 3 txns, $172.49 — running total $172.49
  batch 2: 3 txns, $403.65 — running total $576.14
  batch 3: 3 txns, $325.34 — running total $901.48
max batches in flight: 1

Lado a lado

Dart nativo

FxDart

Por qué difieren

Seamos justos: una importación estrictamente secuencial es la única política de concurrencia que un simple bucle for maneja con elegancia, y la versión nativa se lee bien —slices de package:collection hasta cubre el troceado en lotes—. El total acumulado, en cambio, ya es estado mutable hilado a mano (running += amount junto a n++), mientras que scan lo convierte en un paso declarado. Y la sencillez del bucle es un callejón sin salida: el día que el endpoint permita dos lotes concurrentes, la versión con FxDart cambia 1 por 2, mientras que el bucle se convierte en el pool de workers de los otros ejemplos asíncronos. La cadena enuncia la política; el bucle la codifica.

Benchmark

Apple M1 Max, 32 GB de RAM · Dart 3.12.2 (compilado AOT) · 2026-08-24

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

Dart nativo 156 µs
FxDart 177 µs

Memoria pico Empate

Dart nativo 16.5 MB
FxDart 16.8 MB

N = 10,000

Tiempo Gana nativo

Dart nativo 12.7 ms
FxDart 17.3 ms

Memoria pico Gana nativo

Dart nativo 24.0 MB
FxDart 27.5 MB

N = 100,000

Tiempo Gana nativo

Dart nativo 131.0 ms
FxDart 157.7 ms

Memoria pico Empate

Dart nativo 75.9 MB
FxDart 79.7 MB

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í.