Skip to content

When to use sharedbox

Should you use a box, or would something simpler do? A box is made for sharing a record between processes, and that has a price: every read and write turns the value into bytes in shared memory or back, which costs some tens to hundreds of nanoseconds, and every read gives you a copy.

If all your code runs in threads of one process, you don't need to pay that price: threads can share ordinary Python objects, which is several times faster and works with any Python type. psygnal's evented dataclasses give such an object the same events interface as a box, and a threading.Lock makes several changes appear at once, as update does:

import threading
from dataclasses import dataclass

from psygnal import evented


@evented
@dataclass
class Motor:
    position: int = 0
    enabled: bool = False


motor = Motor()
lock = threading.Lock()
motor.events.position.connect(lambda new, old: print(old, "->", new))
with lock:
    motor.position = 10              # prints: 0 -> 10

Unlike a box's signals, these callbacks run on the thread that changes the field, before the assignment returns. A box's callbacks run on its watcher thread; Waiting for changes explains why.