6 ms·
Zig’s Io.Threaded is neat
- two_handfuls 28d agoOh man this finishes too early, I would want to read more!
- skrebbel 28d agoIt got cancelled halfway
- memco 27d agoAgreed. There's this line: > Wouldn’t it be cool if we could just use standard OS threads, blocking APIs, avoid new shinies like io_uring, but still get to cancel any work reliably? Wish more was said about this: why would that be cool? I get that having robust cancellation in standard threads is cool, but why do we want to avoid io_uring?
- LoganDark 27d ago> why do we want to avoid io_uring? io_uring has been one of the greatest sources of exploits for the Linux kernel in years. io_uring has resulted in so many practical privilege escalation attacks that many containers completely block it, and companies like Google keep it entirely disabled. RHEL also ships a kernel without it by default.
- lukaslalinsky 27d agoProgramming asynchronous code is hard. Execution is split up, you have extra state machine to handle, extra resources to manage that need to survive across async boundaries. And by asynchronous, I mean either callbacks or manually checked completions from some event system. Modern languages hide that under async/await, which is much better from DX perspective, but still leads to split in the ecosystem, and it's hard to optimize across async boundaries. This is an example why Go is such a successful language, in my view. It hides the async complexity and allows you to pretend you have a simple continuous thread of execution. It's just cheaper than system threads. Imagine if operating system threads and the blocking syscalls were this efficient. I've spent the last year building a similar runtime for Zig. Purely because I want my applications to forget they are using things like io_uring in the background.
- zuzululu 28d agoI'm shipping in Rust but any reason to do so in Zig ? What does it offer over Rust ? Something tangible benefit to end user or developer using ai assisted development ?
- rahen 28d agoUse Rust if you're not writing code yourself. The borrow checker will catch all kinds of bugs that AI-generated code will happily compile in Zig but will blow up as UB at runtime. Zig's value prop is different and closer to a modern C: it fits in your head and maps fairly closely to assembly. There is no hidden control flow or hidden allocations, so you can tweak performance at a very low level. You're the pilot, not the compiler. Rust trades the low-level clarity for compiler-enforced safety. If you're not a code artisan or don't care about being one, then please use Rust.
- eptcyka 28d ago> You're the pilot, not the compiler. This to me reads like an LLMism.
- solatic 28d ago> The borrow checker will catch all kinds of bugs that AI-generated code will happily compile in Zig but will blow up as UB at runtime. This has not been my experience; Claude does a great job of writing unit tests for the Zig code, and combined with Zig's fuzzing features and a Python-based integration testing suite, I have avoided hitting runtime UB so far. In exchange, I get much faster compile times, which are important for the agentic development loop.
- zuzululu 28d agoCan LLMs not write Zig code ? I'm not really understanding your explanation for why we can write other languages with LLM but not Zig here. > Rust trades the low-level clarity for compiler-enforced safety. If you're not a code artisan or don't care about being one, then please use Rust. Not really seeing the connection here. What do you mean by code artisan? Are you trying to gatekeep Zig because you think Zig is too difficult for LLMs?
- phplovesong 28d agoI know syntax does not REALLY matter, but Zig is just kind of subpar syntax wise. Its really verbose and picked weirdly from what already exists. Zig code is usually hard to read because it really noicy, and has weird things not existing in other languages without merit.
- pzittlau 28d agoI don't think that it's really subpar. It's just unusual compared to others. In and of itself it's very consistent. For instance there's `|capture|` for capturing all sort of things(errors, optionals, ...) in nearly all control flow constructs. `blk:` for naming blocks, `if`s, `switch`, and so on. Have a look at this blog post: https://matklad.github.io/2025/08/09/zigs-lovely-syntax.html https://matklad.github.io/2025/08/09/zigs-lovely-syntax.html
- phplovesong 28d agoI saw that article previously. Nearly all of the syntax seem to be in-house with little benefit. All the examples could just use some modern c-like thing. Zig has benefits, like comptime, no hidden control flow, memory mngmt, cross compilation etc. But its syntax is just a mouthfull of wats, whys and wtfs. I can forsee a compile to Zig languge popping up sometime soon.
- ulbu 28d ago|capture| hides an inconsistency that bugs me – everywhere else, assignment to a variable flows leftwards. |capture| is an unnatural rightwards assignment. in general, I like zig syntax, but i find that it had very little regard to how the eye moves on the page. it’s jarring at times.
- simjnd 28d agoBut the capture is conditional so it makes sense. if (evaluation) result = evaluation if (evaluation) |result| Although assignments as expressions in C are convenient, I don't think they make a ton of sense and find Zig's capture easier to read (easier to immediately see what's being evaluated)
- lll-o-lll 28d agoAll my days of low level stuff were in the windows world where async/cancel was supported since nt kernel days at least. Wrapping this coherently at some level of abstraction was always worth doing, although threads are just one way. Overlapped I/O let you do it all on one thread. Linux looks harder. Great that Zig is supporting this more “first class”; not strictly required, but looks useful.
- lukaslalinsky 27d agoIf you are comparing to overlapped I/O, you should use io_uring as reference and cancellation in io_uring is fairly simple.
- deleted 27d ago[deleted]
- _old_dude_ 28d agoJust here to say that Java as interruptible channels since the beginning of 2000. You can interrupt a blocking IO operation with either interrupt() or close(). https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/nio/channels/InterruptibleChannel.html https://docs.oracle.com/en/java/javase/25/docs/api/java.base...
- dtj1123 28d agoName checks out.
- gdcbe 28d agoYou might want to read the “prior art” section of their article…
- embedding-shape 28d agoWho's right though? The article seems to go directly against what parent said above? > In Java, there’s a similarly looking thread interruption mechanism. Critically, it doesn’t support interrupting syscalls: IOException and InterruptedException are both checked and unrelated, meaning that IOing functions are not interruptible One says IOing functions are not interruptible, other says "You can interrupt a blocking IO operation" :)
- Sharlin 28d agoThe article seems to talk about how `Thread.interrupt` works with synchronous IO, rather than the async IO machinery of `java.nio`. So I'd say the article is inaccurate or at least incomplete.
- lowbloodsugar 27d agoNIO can be blocking or non-blocking. Indeed you can switch between the two on a single channel.
- twic 28d ago
- fenestella 28d agoThe way Zig handles the transition between synchronous and asynchronous I/O without requiring a heavy runtime is a masterclass in systems design. I'm particularly interested in how this approach to blocking calls might simplify mobile development where thread-per-request isn't always feasible but async/await coloring remains a pain. Does this implementation handle thread pool exhaustion gracefully if a large number of 'threaded' tasks block simultaneously?
- inglor 28d agoCool writeup but... Signals are not some opaque or roundabout feature to do this. Signals are a thing for a reason and this is how it's implemented in any threaded I/O library I've read.
- eptcyka 27d agoYe, but signals are cumbersome and a foot gun. Should a library ever install signal handlers? What about languages with runtimes? Ever read the spec on how go handles signals differently depending on how it is compiled?
- Asmod4n 27d agohow do they handle that malloc aint async signal safe?
- comex 27d agoYou don’t have to do any significant work within the signal handler itself. In fact, the signal handler can literally be empty. What matters is that as long as SA_RESTART is not set, after the signal handler runs, the interrupted syscall fails with errno set to EINTR. Then the code that did the syscall can check whether a cancellation occurred (and retry the syscall if not). Disclaimer: I haven’t looked at Zig’s implementation; I’m only going off how the Unix APIs work.
- up2isomorphism 27d agoJust use C, these are well understood things 20 years ago.