Skip to content

Effects

Preview — Ranvier is pre-release; its APIs may change.

Effects are the push side of the graph: nothing reads them, so the scheduler runs them. A write that reaches an effect therefore pays for queueing and flushing on top of notification. See Benchmarks for configuration, environment and caveats.

EffectBenchmarks

One signal observed by Effects effects (1, 8 or 64).

MethodWhat it measures
WriteAndFlushOne write, then the flush that runs every effect the write invalidated.
BatchOfTenWritesTen writes inside one batch, followed by a single flush that runs each effect once.

Recorded 2026-09-28. Source: Ranvier.Benchmarks.Effects.EffectBenchmarks at commit d87920f.

MethodEffectsMeanErrorStdDevOp/sAllocated
WriteAndFlush117.81 ns0.184 ns0.154 ns56,133,012.1-
BatchOfTenWrites136.89 ns0.311 ns0.276 ns27,104,757.4-
WriteAndFlush8114.76 ns1.007 ns0.841 ns8,713,660.1-
BatchOfTenWrites8179.76 ns2.292 ns2.032 ns5,562,912.3-
WriteAndFlush64835.32 ns6.463 ns5.729 ns1,197,153.0-
BatchOfTenWrites641,298.42 ns13.692 ns12.138 ns770,167.6-

BatchOfTenWrites performs ten writes per operation where WriteAndFlush performs one, so the rows are not comparable per operation. The batch row shows the cost of ten writes that share one flush.

FieldWriteBenchmarks

One field of a Fields-field model (8, 64 or 256) changed per write, with one effect per field. The model is an int[], so a copy costs what copying a record of Fields fields costs. See Elmish for the patterns compared.

MethodWhat it measures
FieldSignalWriteBaseline. A write to one field's own signal, waking its one effect. Flat in Fields.
SelectorMemoWriteA copy of a root signal's model with one field changed, re-running all Fields selector memos and waking one effect.
MvuDispatchSelectorMemoWrite through Mvu.Dispatch and Mvu.Select.
ModelCopyOnlyThe model copy alone: the part of SelectorMemoWrite spent outside the graph.

The counter scenario mvu-dispatch compares a signal per field (FieldSignalWrite) with Mvu.Dispatch (MvuDispatch) at 64 fields. Figures are retired instructions per operation at commit e13f159, .NET 10 with tiered compilation and PGO off (see Instruction counts):

Variantinstr/opbytes/opLibrary counters/op
A signal per field6070EffectRuns 1, Flushes 1
Mvu.Dispatch48,133400MemoRecomputes 64, EffectRuns 1, Flushes 1

A dispatch costs about 80 times a field signal write: every observed selector re-runs, 64 recomputes per dispatch. SelectorMemoWrite, ModelCopyOnly and the 8- and 256-field cases are in the suite for local runs (dotnet run --project bench/Ranvier.Benchmarks -c Release -- --filter "*FieldWriteBenchmarks*") and have no published figure yet. The full report is e13f159.md.

EditableBenchmarks

A writable derived value (createEditable) against a plain signal, each read by one effect.

MethodWhat it measures
PlainSignalWriteBaseline. One signal write, waking one effect.
LocalEditA local edit, waking the effect that reads the editable.
UpstreamChangeAn upstream write propagating through the source, the seed, the editable and the effect.

The counter scenarios editable-edit and editable-upstream measure the same two writes over 1000 editables, each read by one effect. One operation writes every 10th editable, 100 writes in all. Figures are retired instructions per operation at commit e13f159, .NET 10 with tiered compilation and PGO off (see Instruction counts):

Scenarioinstr/opbytes/opLibrary counters/op
editable-edit145,0060MemoRecomputes 100, EffectRuns 100, Flushes 100
editable-upstream194,4492,400MemoRecomputes 200, EffectRuns 100, Flushes 100

A local edit costs about 1,450 instructions and allocates nothing; an upstream write costs about 1,940 instructions and 24 bytes, and recomputes two memos per write. PlainSignalWrite has no counter scenario of its own and no published figure yet; the timing cases are in the suite for local runs (dotnet run --project bench/Ranvier.Benchmarks -c Release -- --filter "*EditableBenchmarks*"). The full report is e13f159.md.

Edit this page