Pipeline de liquidación de cierre de día
Requisito
Cierra el día. A partir de diez transacciones con tarjeta (en el código
de abajo): descarta las failed, agrupa el resto por
comercio y calcula el neto de cada comercio (los reembolsos van en
negativo). Publica la liquidación de cada comercio en la pasarela
bancaria — como mucho dos publicaciones en vuelo, con
los resultados en orden de comercio — y luego imprime el informe: una
línea por comercio, un desglose entre pagos y cobros (los reembolsos de
un comercio superan sus cargos), el total general y la prueba del máximo
en vuelo.
Esta es la librería entera en un solo pipeline. Preparación síncrona:
reject → groupBy → sumBy por
grupo → sortBy. Cruza a asíncrono con toAsync
y publica bajo concurrent(2). El informe usa de nuevo
partition y sumBy.
Salida esperada
2026-07-27 close — 3 merchants, 2 postings at a time: BookNook: 3 txns, net $-6.01 Cafe Luna: 4 txns, net $32.00 GadgetHub: 2 txns, net $218.90 payouts: 2, collections due: 1 settled: $244.89 max postings in flight: 2
Lado a lado
Dart nativo
FxDart
Por qué difieren
Cada mitad de esta tarea ya ha aparecido en un ejemplo más pequeño; lo
interesante aquí es qué ocurre cuando se juntan. Dart nativo resuelve la
preparación bastante bien con package:collection
(groupListsBy, sortedBy) — aunque sacar el neto
de cada grupo es un fold con un valor inicial explícito, y
el desglose de pagos son dos pasadas de where. Después llega
la frontera asíncrona y la forma se rompe: la publicación acotada
necesita el pool de workers, una función aparte con nombre, con slots y
un cursor, y el pipeline que venías leyendo se convierte en fontanería
que tienes que seguir a mano. La versión con FxDart es una única cadena
ininterrumpida desde las transacciones en bruto hasta las liquidaciones
publicadas — catorce líneas en las que la política (qué es válido, cómo
agrupar, con cuánta fuerza golpear la pasarela) es el texto visible, y la
mecánica es problema de la librería.
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 FxDart
Memoria pico Gana nativo
N = 100,000
Tiempo Gana FxDart
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í.