Gasto agrupado por categoría
Requisito
Totaliza nueve transacciones de agosto por categoría, e imprime los totales en el orden en que cada categoría aparece por primera vez en el extracto. Los datos están en el código; las dos versiones deben imprimir las líneas que aparecen bajo Salida esperada.
Salida esperada
groceries: 69 transport: 23 dining: 72
Lado a lado
RxDart
FxDart
Por qué difieren
El agrupado es donde el compromiso del modelo push con «todo es un
stream» sale caro. El groupBy de RxDart no puede devolver
un mapa — la fuente podría no terminar nunca — así que devuelve un
stream de streams: un GroupedStream por cada
clave nueva. Para sacar los totales, cada stream interno debe plegarse
(un Future), el future elevarse de vuelta a stream
(asStream) y los resultados mezclarse con
flatMap — tres capas de fontanería alrededor de un
sum. (Un usuario rx pragmático puede esquivar
groupBy por completo plegando el stream entero en un mapa
mutable — más corto, pero abandona el operador del que trata este
ejemplo y el agrupado vuelve a ser imperativo.) Y la forma tiene
aristas afiladas: pliega con asyncExpand en lugar de
flatMap y el programa entra en deadlock, porque pausar el
stream exterior mientras se espera el total de un grupo detiene la
fuente que debe completarse antes de que ningún grupo pueda cerrarse.
Los datos de FxDart son finitos por construcción, así que agrupar no
necesita streams-de-streams: groupedBy produce records
(key, items) corrientes en orden de primera aparición de
la clave y la cadena sigue adelante, con sumBy haciendo
la aritmética por grupo. Nada se aplaza porque nada sigue llegando.
Para feeds vivos e ilimitados el diseño de GroupedStream es la
decisión correcta — pero para un extracto que ya está en la mano, este
es un trabajo con forma de pull y la versión pull lo dice en tres
líneas. El veredicto se lo lleva FxDart.
Benchmark
N = 100
Tiempo Empate
Memoria pico Empate
N = 1,000,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í.