Tamschi / flourish

flourish is a convenient and full-featured signals framework in Rust. isoprenoid is the signals SDK backing flourish.
https://crates.io/crates/flourish
17 stars 0 forks source link

linearise updates more efficiently #9

Open Tamschi opened 1 week ago

Tamschi commented 1 week ago

Is your feature request related to a problem? Please describe. Queueing updates in GlobalSignalsRuntime currently takes out a global exclusive lock, which is mildly put less than ideal. This action can be made lock-free and barrier-free between concurrent writes.

This reduces read/write synchronisation essentially to multiple SPSC channels which can likely use compare_exchange with Relaxed failure ordering due to an unbroken series of transaction IDs (see below).

That still leaves congestion of the atomic (see below), but considering that shouldn't be called in a tight loop, it might be irrelevant in that the atomic is likely to be committed to a shared cache naturally before it is accessed again.

Describe the solution you'd like

Describe alternatives you've considered Is this just an MPSC that respects outside memory barriers and doesn't introduce them itself? It may exist already, and if not it likely makes for a useful library. Maybe crossbeam-channel or an explicit SPSC channel library could help (or be used for the thread-associated storage if it allows peeking).

Additional context This is inspired by https://snarfed.org/2019-12-28_39697. Thanks to @snarfed for pointing me in this direction, that was spot-on. I can't quite use transactional memory unfortunately, but my submitted-updates API can still benefit from a very similar implementation.

I'll label this as both work: clear and work: complicated since the approach is straightforward in theory but packaging it nicely may not be. There may also be an existing implementation, which going to need more research to rule out.

Tamschi commented 3 days ago

It seems there's no existing unbounded SPSC I can use for this. I should be able to chain ringbuf FIFOs, though, by storing them in a linked list where the producer holds a reference to the first and the consumer to the last.

Provide a way to add a new small buffer to trim the overall allocation?