Live data from Hacker News

Zig's new plan for asynchronous programs

lwn.net

41–50 of 274 posts

Re: Zig's new plan for asynchronous programs

#41
post #26

I find this example quite interesting: var a_future = io.async(saveFile, .{io, data, "saveA.txt"}); var b_future = io.async(saveFile, .{io, data, "saveB.txt"}); const a_result = a_future.await(io); const b_result = b_future.await(io); In Rust or Python, if you make a coroutine (by calling an async function, for example), then that coroutine will not generally be guaranteed to make progress unless someone is waiting f…

It's not guaranteed in Zig either.

Neither task future is guaranteed to do anything until .await(io) is called on it. Whether it starts immediately (possibly on the same thread), or queued on a thread pool, or yields to an event loop, is entirely dependent on the Io runtime the user chooses.

Re: Zig's new plan for asynchronous programs

#42

I think this design is very reasonable. However, I find Zig's explanation of it pretty confusing: they've taken pains to emphasize that it solves the function coloring problem, which it doesn't: it pushes I/O into an effect type, which essentially behaves as a token that callers need to retain. This is a form of coloring, albeit one that's much more ergonomic. (To my understanding this is pretty similar to how Go sol…

Actually it seems like they just colored everything async and you pick whether you have worker threads or not.

I do wonder if there's more magic to it than that because it's not like that isn't trivially possible in other languages. The issue is it's actually a huge foot gun when you mix things like this.

For example your code can run fine synchronously but will deadlock asynchronously because you don't account for methods running in parallel.

Or said another way, some code is thread safe and some code isn't. Coloring actually helps with that.

Re: Zig's new plan for asynchronous programs

#43
post #38

Earlier quoted context omitted.

Where do you think the Io parameter comes from? If you change some function to do something async and now suddenly you require an Io instance. I don't see the difference between having to modify the call tree to be async vs modifying the call tree to pass in an Io token.

Synchronous Io also uses the Io instance now. The coloring is no longer "is it async?" it's "does it perform Io"? This allows library authors to write their code in a manner that's agnostic to the Io runtime the user chooses, synchronous, threaded, evented with stackful coroutines, evented with stackless coroutines.

Rust also allows writing async code that is agnostic to the async runtime used. Subsuming async under Io doesn't change much imo.

Re: Zig's new plan for asynchronous programs

#44
post #39

Earlier quoted context omitted.

Having used zig a bit as a hobby. Why is it more ergonomic? Using await vs passing a token have similar ergonomics to me. The one thing you could say is that using some kind of token makes it dead simple to have different tokens. But that's really not something I run into often at all when using async.

> The one thing you could say is that using some kind of token makes it dead simple to have different tokens. But that's really not something I run into often at all when using async. It's valuable to library authors who can now write code that's agnostic of the users' choice of runtime, while still being able to express that asynchronicity is possible for certain code paths.

But that can already be done using async await. If you write an async function in Rust for example you are free to call it with any async runtime you want.

Re: Zig's new plan for asynchronous programs

#45
post #39

Earlier quoted context omitted.

> The one thing you could say is that using some kind of token makes it dead simple to have different tokens. But that's really not something I run into often at all when using async. It's valuable to library authors who can now write code that's agnostic of the users' choice of runtime, while still being able to express that asynchronicity is possible for certain code paths.

But that can already be done using async await. If you write an async function in Rust for example you are free to call it with any async runtime you want.

But you can't call it from synchronous rust. Zig is moving toward all sync code also using the Io interface.

Re: Zig's new plan for asynchronous programs

#46
post #6

I'm excited to see where this goes. I recently did some io_uring work in zig and it was a pain to get right. Although, it does seem like dependency injection is becoming a popular trend in zig, first with Allocator and now with Io. I wonder if a dependency injection framework within the std could reduce the amount of boilerplate all of our functions will now require. Every struct or bare fn now needs (2) fields/param…

Yes, and it's good that way.

Please, anything but a dependency injection framework. All parameters and dependencies should be explicit.

Re: Zig's new plan for asynchronous programs

#47
post #26

I find this example quite interesting: var a_future = io.async(saveFile, .{io, data, "saveA.txt"}); var b_future = io.async(saveFile, .{io, data, "saveB.txt"}); const a_result = a_future.await(io); const b_result = b_future.await(io); In Rust or Python, if you make a coroutine (by calling an async function, for example), then that coroutine will not generally be guaranteed to make progress unless someone is waiting f…

C# works like this as well, no? In fact C# can (will?) run the async function on the calling thread until a yield is hit.

Re: Zig's new plan for asynchronous programs

#48
post #42

I think this design is very reasonable. However, I find Zig's explanation of it pretty confusing: they've taken pains to emphasize that it solves the function coloring problem, which it doesn't: it pushes I/O into an effect type, which essentially behaves as a token that callers need to retain. This is a form of coloring, albeit one that's much more ergonomic. (To my understanding this is pretty similar to how Go sol…

Actually it seems like they just colored everything async and you pick whether you have worker threads or not. I do wonder if there's more magic to it than that because it's not like that isn't trivially possible in other languages. The issue is it's actually a huge foot gun when you mix things like this. For example your code can run fine synchronously but will deadlock asynchronously because you don't account for m…

> Actually it seems like they just colored everything async and you pick whether you have worker threads or not.

There is no 'async' anywhere yet in the new Zig IO system (in the sense of the compiler doing the 'state machine code transform' on async functions).

AFAIK the current IO runtimes simply use traditional threads or coroutines with stack switching. Bringing code-transform-async-await back is still on the todo-list.

The basic idea is that the code which calls into IO interface doesn't need to know how the IO runtime implements concurrency. I guess though that the function that's called through the `.async()` wrapper is expected to work properly both in multi- and single-threaded contexts.

Re: Zig's new plan for asynchronous programs

#49
post #4

I’m excited to see how this turns out. I work with Go every day and I think Io corrects a lot of its mistakes. One thing I am curious about is whether there is any plan for channels in Zig. In Go I often wish IO had been implemented via channels. It’s weird that there’s a select keyword in the language, but you can’t use it on sockets.

At least Go didn't take the dark path of having async / await keywords. In C# that is a real nightmare and necessary to use sync over async anti-patterns unless willing to re-write everything. I'm glad Zig took this "colorless" approach.

[dead]

Re: Zig's new plan for asynchronous programs

#50
post #42

Earlier quoted context omitted.

Actually it seems like they just colored everything async and you pick whether you have worker threads or not. I do wonder if there's more magic to it than that because it's not like that isn't trivially possible in other languages. The issue is it's actually a huge foot gun when you mix things like this. For example your code can run fine synchronously but will deadlock asynchronously because you don't account for m…

> Actually it seems like they just colored everything async and you pick whether you have worker threads or not. There is no 'async' anywhere yet in the new Zig IO system (in the sense of the compiler doing the 'state machine code transform' on async functions). AFAIK the current IO runtimes simply use traditional threads or coroutines with stack switching. Bringing code-transform-async-await back is still on the tod…

> There is no 'async'

I meant this more as simply an analogy to the devX of other languages.

>Bringing code-transform-async-await back is still on the todo-list.

The article makes it seem like "the plan is set" so I do wonder what that Todo looks like. Is this simply the plan for async IO?

> is expected to work properly both in multi- and single-threaded contexts.

Yeah... about that....

I'm also interested in how that will be solved. RTFM? I suppose a convention could be that your public API must be thread safe and if you have a thread-unsafe pattern it must be private? Maybe something else is planned?

Post reply on HN