19 Dec 2020
Today I’m releasing capnproto-rust version 0.14.
The main change is a new
sync_reader
feature that allows messages to be shared between multiple threads.
With the new feature, you can, for example, wrap a capnp::message::Reader
with lazy_static or
once_cell and then read it from anywhere else
in your program.
Previously, doing so was not possible because the
message traversal limit
was tracked through a Cell, causing message::Reader to not be
Sync.
Now, when sync_reader is enabled, the traversal limit
is tracked through an AtomicUsize, which can be safely
shared between threads.
To minimize the performance impact, the new implementation uses
Ordering::Relaxed when accessing the atomic counter.
When I measured the performance on a few benchmarks,
I was initially discouraged because
fetch_sub()
seemed to be slowing things down significantly.
Fortunately, I found that splitting fetch_sub() into separate load() and store()
steps recovered the lost time.
(Such a split may cause the read limiter to undercount reads,
but we are okay with that level of imprecision.)
With the most recent version,
I am unable to detect any speed difference between the new atomic implementation
and the old Cell-based one.
I would have liked to unconditionally enable atomic read limiting,
but unfortunately AtomicUsize is not available on all platforms.
For example, rustc
does not support any atomics on
riscv32i-unknown-none-elf.
(I am unsure whether that’s an inherent property of the platform,
or whether it’s an implementation hole that could be filled in later.)
@appaquet deserves credit for submitting the pull request with this change and for patiently iterating on it with me.