3 ms·
> The standard way to avoid these problems is to use locks to prevent data updates from happening at the same time. This causes big performance hits […] No. Mo
by adwn 1y ago
> The standard way to avoid these problems is to use locks to prevent data updates from happening at the same time. This causes big performance hits […]
No. Modern mutex implementations [1] are extremely efficient, require only 1 byte of memory (no heap allocation), and are almost free when there's no contention on the lock – certainly much faster and much lower latency than sending messages between actors.
[1] Like the parking_lot crate for Rust.
- otabdeveloper4 1y agoA contended mutex is a system call and likely stalls all the CPUs on your machine. Lockfree spinlocks will only waste cycles on one CPU. A huge difference when you have dozens and hundreds of cores.
- adwn 1y ago> A contended mutex is a system call […] Because modern mutexes are so cheap (only 1 byte directly in the data structure, no heap allocation), you can do very fine-grained locking. This way, a mutex will almost never be contended. Keep in mind that a reader waiting on an empty queue or a writer waiting on a full queue will also involve syscalls. > […] and likely stalls all the CPUs on your machine. Huh? Where did you get this idea? Only the waiting thread will be blocked, and it won't "stall" the core, let alone the entire CPU. By the way, if all your threads are waiting on a single mutex, then your architecture is wrong. In the equivalent case, all your actors would be waiting on one central actor as well, so you'd have the same loss of parallelism.
- gpderetta 1y agoSo does a contended queue. As much as I might like the model, message passing is not a silver bullet. Any sufficiently complex message passing system will end up implementing shared memory on top of it... and mutexes.
- alfanerd 1y agoSending a message between Actors can be just moving a pointer to a piece of shared memory. I think sending messages is more about the way you think about concurrency, more than the implementation. I have always found the "one thread doing "while True receive message, handle message" much easier to reason about than "remember to lock this chunk of data in case more than one thread should access it"
- gpderetta 1y agoUnless you have NxN queues across actors[1], which is done on some specialized software but is inherently not scalable, queues will end up being more complex than that. [1] at the very least you will need one queue for each cpu pair, but that's yet another layer of complication.
- alfanerd 1y agoI think you only need one queue per actor? And then one worker per CPU core? I believe that how Erlang does it, and do millions of actors without any issues...
- gpderetta 1y agoYes, but now you have contention on the queue.
- ramchip 1y agoThe way Erlang does it is to use buckets so it looks like a single queue to the user code but really is more like multiple queues behind the scene. Scales extremely well. It's certainly not "just moving a pointer to a piece of shared memory" though... https://www.erlang.org/blog/parallel-signal-sending-optimization/ https://www.erlang.org/blog/parallel-signal-sending-optimiza...
- __red__ 1y agoPony schedulers default behaviour is as follows: 1. One scheduler per core. 2. Schedulers run one actor behaviour at a time. 3. When a scheduler has an empty work queue, they will steal work from other schedulers. 4. The number of schedulers will scale up and down with the amount of work (but never more than number of cores). There are various parameters you can change to alter scheduler behaviour should your pattern of use need it.
- adwn 1y ago> Sending a message between Actors can be just moving a pointer to a piece of shared memory. No, you also need synchronization operations on the sending and the receiving end, even if you have a single sender and a single receiver. That's because message queues are implemented on top of shared memory – there's no way around this on general-purpose hardware.
- adwn 1y agoWhy is this downvoted? It's factually correct, on-topic, and relevant (because it contradicts a claim on the linked website). If you disagree, say so and we can discuss it.
- senderista 1y agoNit: you can’t have a 1-byte mutex unless you implement your own wait queues like parking_lot does. Any purely futex-based mutex (ie delegating all the blocking logic to futex syscalls) must be at least 4 bytes.