fork
Ramifica una única iteración con buffer de una fuente en lectores independientes y reproducibles.
Lección
Iterar dos veces el mismo objeto Iterable de Dart normalmente
ejecuta su fuente dos veces — un generador sync* vuelve a
empezar desde cero cada vez que pides un .iterator nuevo. Eso
es un derroche (o directamente un error) cuando producir un valor sale
caro: una petición de red, un cálculo lento, un stream que solo puedes
leer una vez. fork lo arregla: cada llamada a
fork(iterable) con el mismo objeto
iterable devuelve un cursor independiente sobre un único
buffer compartido que crece de forma perezosa. La fuente subyacente se
recorre exactamente una vez, sin importar cuántos forks lean de ella ni en
qué orden.
La compartición se indexa por la identidad del iterable que
pasas (mediante un Expando interno), así que debes hacer fork
del mismo objeto — no de dos iterables construidos por separado
que casualmente se parezcan. Cada fork puede consumirse a su propio ritmo:
adelantarse en un fork tira de nuevos valores de la fuente y los añade al
buffer compartido; un fork que va rezagado simplemente reproduce los
valores que ya están en el buffer, sin coste adicional.
forkAsync funciona igual para FxAsyncIterable y,
además, permite que la demanda concurrente de varios forks aguas abajo
tire de la fuente asíncrona compartida en paralelo.
Demo 1 · Una fuente, dos ramas, demostrado con un contador
source() incrementa calls cada vez que produce
un valor. Tanto evens como doubled hacen fork
del mismísimo objeto shared — si la fuente se ejecutara dos
veces, calls acabaría en 10, no en 5:
Demo 2 · Forks a ritmos distintos comparten un solo buffer
La rama a se adelanta y tira de dos valores nuevos; cuando la
rama b pide sus dos primeros, simplemente reproduce lo que
a ya había almacenado — sin nuevas llamadas a
source() hasta que b necesita un tercer valor
que ningún fork ha visto todavía:
Pruébalo tú
Ejercicio: ahora mismo readings se itera dos veces sin
fork, así que sensor() se ejecuta dos veces y
reads acaba en 6. Haz fork de readings para cada
consumidor de modo que el sensor se lea una sola vez (reads
debería ser 3).
peek — observar sin ramificar ·
concurrent — evaluación paralela dentro de una sola rama ·
memoize — cachear un único valor en lugar de una secuencia entera