RCU — The Standard Technique for Read-Optimized Concurrency TODO
Concept
RCU is a synchronization technique for read-heavy data structures that lets readers reference data without any locks or atomic writes. Instead of modifying an existing node in place, an updater builds a modified copy and swaps the pointer over in a single atomic publish, so a reader always sees one consistent state — either the old version or the new one, never something in between. At publish time, memory ordering has to guarantee that the new node's initialization becomes visible before the pointer swap does. Freeing the old version immediately would break any reader still reading it, so reclamation waits for a grace period — the point at which every pre-existing reader is guaranteed to have exited its critical section. The net effect is read cost converging to nearly zero, at the cost of delayed reclamation and higher memory usage for the updater.
In routing tables, config snapshots, and symbol tables where the read-to-write ratio is heavily skewed, a mutex or RW-lock destroys scalability purely from cache-line contention, and RCU-family techniques remove that bottleneck.
Code & Formula
# RCU(Read-Copy-Update) — 갱신자는 복사본을 고쳐 포인터를 원자적으로 교체하고, 독자는 락 없이 항상 일관된 스냅샷만 본다.
import threading
import time
class RcuBox:
def __init__(self, initial):
self._ptr = initial # 단일 참조 슬롯 — 이 슬롯 교체 하나가 "발행(publish)" 원자 연산
def read(self):
return self._ptr # 독자: 락 없이 현재 포인터만 읽는다 — 항상 완전한 옛 버전 또는 새 버전
def update(self, mutate_fn):
old = self._ptr
new = dict(old) # 복사본을 만들어 그 위에서만 수정 (기존 독자가 보는 old 는 절대 안 건드림)
mutate_fn(new)
self._ptr = new # 원자적 포인터 교체 = 발행. 이 순간 이후 신규 독자는 new 만 본다.
return old # 회수는 유예 기간 이후에(여기서는 즉시 반환만 시연)
config = RcuBox({"rate_limit": 100, "region": "kr"})
seen_versions = []
def reader(idx):
for _ in range(5):
snapshot = config.read() # 항상 완전한 dict 하나 (반쯤 갱신된 상태를 절대 보지 않음)
seen_versions.append(dict(snapshot))
time.sleep(0.001)
readers = [threading.Thread(target=reader, args=(i,)) for i in range(4)]
for t in readers:
t.start()
old_snapshot = config.update(lambda d: d.__setitem__("rate_limit", 500)) # 갱신자: 복사 -> 수정 -> 교체
for t in readers:
t.join()
consistent = all(v in ({"rate_limit": 100, "region": "kr"}, {"rate_limit": 500, "region": "kr"}) for v in seen_versions)
print("old snapshot untouched:", old_snapshot)
print("current snapshot:", config.read())
print("every reader saw a fully-consistent old-or-new version:", consistent)
docs/code/algorithms/algorithms-38.py
Exercise
In Go or Rust, build a copy-on-write cache that swaps a config struct through an atomic pointer, spin up several reader threads, and benchmark throughput against a mutex-based version.
Practical Connection
For a node's state trie cache or an in-memory order book snapshot, where many lookup goroutines face off against a small number of updates, epoch-based reclamation or atomic snapshot swapping is the standard way to get a consistent view without lock contention.
Where it lands in Jayverse
- Verex: swap the order-book/market-state cache with an atomic pointer instead of a mutex. Reads (quote lookups) vastly outnumber writes (new orders), which is exactly the read-heavy shape RCU is for — a lock here is pure cache-line contention.
- Devnet: use epoch-based reclamation for any hosted-Anvil config or state snapshot service with many readers. A copy-on-write swap avoids the RW-lock bottleneck the same way it does for a routing table or symbol table.
- Wallet: read the simulate-before-sign state snapshot through an atomic swap, not a lock. Simulation latency matters per signature request, and RCU-style publish keeps concurrent simulations from blocking on each other.
Key expressions
| Expression | 뜻 · 쓰이는 자리 |
|---|---|
| read-heavy | 읽기 작업이 압도적으로 많은 · "for read-heavy data structures" |
| in place | 그 자리에서 그대로(복사 없이) · "Instead of modifying an existing node in place" |
| atomic publish | 중간 상태 없이 한 번에 반영하는 것 · "swaps the pointer over in a single atomic publish" |
| grace period | 유예 기간 · "reclamation waits for a grace period" |
| reclamation | 다 쓴 메모리를 회수하는 일 · "delayed reclamation and higher memory usage" |
| cache-line contention | 캐시 라인을 두고 벌어지는 경합 · "purely from cache-line contention" |
| converge to | (값·비용이) 점점 수렴하다 · "read cost converging to nearly zero" |
| RCU | Read-Copy-Update · 락 없이 읽기 성능을 높이는 동시성 기법, 읽기가 압도적으로 많은 자료구조에 쓰인다. "RCU is a synchronization technique for read-heavy data structures" |
If you study this on a given day, add a note link and a ✅ to this line in the source curriculum (docs/knowledge/dev-100-curriculum.md) and this spot will lead straight to the note body. You can also write directly on this page — but regenerating overwrites it, so it's safer to keep anything you want to save as markdown under docs/algorithms/.