Scalar Select Anti-Pattern
68 points by matklad
68 points by matklad
this sort of thing comes up in gamedev
you’ll have a scalar select, and then when the queue is empty it’ll update and render. but, the scalar select is usually lightweight, and just puts the relevant parts of the event somewhere for the update function to deal with
like, a keyboard event will get grouped by key, and the presses/releases get counted (coalescing). the actual “make the character jump” part happens in the update function, usually in a specified order. if the character is mid-attack, you’ll often discard button presses
potentially obvious caveat: you should have some limit to the batch size, otherwise you can get stuck with a never-ending incoming stream and just obliterate memory >.<
Generally, you wouldn’t: next_non_blocking is non-blocking, it won’t do any syscalls, so you won’t receive more than whatever is the size of the underlying buffer you read
into.
That’s the subtlety here: you can do debouncing where you just wait, say, 16 ms, between draining the events, but that I think would be a bad idea in general. Instead, you should only process things you’ve already received, and nothing more.
This still can be an issue if you have, eg, two threads that communicate via a lock-free queue, but I think such scenarios shouldn’t be arising naturally.
I don’t understand your explanation re: buffer you read into. Are you saying that:
I came to say the same as GP. I suspect we were both confused as the article didn’t note the pure userspace semantics of next_non_blocking.
For context, I’ve used this same pattern in a real-time embedded environment; there next_non_blocking was copying from a DMA ring buffer. I’ve also used it for consuming from a Kafka topic; there next_non_blocking made a syscall. In both circumstances, I explicitly capped batch size to moderate system behaviour.
I also encountered this multiple times and I agree that this is right solution, but one problem with batch handling is that if you are reading from some sort of a persistent queue (like RabbitMQ), the ack-ing and error handling become much harder.
IMO this kind of scenarios where errors as values shine. With list of results you can handle it very easily if your queue supports batch packing
I couldn’t find any official docs defining Zig’s select!
(or select
, if the !
has something to do with Zig’s error handling). I found open issue zig#5263, which discusses adding select
syntax, and the article Concurrency in Zig, which says “The select
statement allows you to wait for multiple channel operations simultaneously, enabling non-blocking communication.” I also found select
(Unix), a Unix system call that the keyword is probably named after.