Live data from Hacker News

Zig's New Async I/O

kristoff.it

221–230 of 293 posts

Re: Zig's New Async I/O

#221
post #8
post #3

I feel that I have to point this out once again, because the article goes so far as to state that: > With this last improvement Zig has completely defeated function coloring. I disagree with this. Let's look at the 5 rules referenced in the famous "What color is your function?" article referenced here. > 1. Every function has a color Well, you don't have async/sync/red/blue anymore, but you now have IO and non-IO fun…

The key difference to typical async function coloring is that `Io` isn't something you need specifically for asynchronicity; it's something which (unless you make a point to reach into very low-level primitives) you will need in order to perform any IO, including reading a file, sleeping, getting the time, etc. It's also just a value which you can keep wherever you want, rather than a special attribute/property of a…

> * It's quite rare for a function to unexpectedly gain a dependency on "doing IO" in general.

I don't know where you got this, but it's definitely not the case, otherwise async would never cause problems either. (Now the problem in both cases is pretty minor, you just need to change the type signature of the call stack, which isn't generally that big, but it's exactly the same situation)

> In practice, most of your codebase will have access to an `Io`, and only leaf functions doing pure computation will not need them.

So it's exactly similar to making all of your functions async by default…

Re: Zig's New Async I/O

#222
post #8

Earlier quoted context omitted.

The key difference to typical async function coloring is that `Io` isn't something you need specifically for asynchronicity; it's something which (unless you make a point to reach into very low-level primitives) you will need in order to perform any IO, including reading a file, sleeping, getting the time, etc. It's also just a value which you can keep wherever you want, rather than a special attribute/property of a…

> Arguably, our solution to the problem is just to color every function async-colored. This is essentially how Golang achived color-blindness.

It's basically how Java does it (circa 17) as well.

It's something you really can't do without a pretty significant language runtime. You also really need people working within your runtime to prefer being in your runtime. Environments that do a lot of FFI don't work well with a colorblind runtime. That's because if the little C library you call does IO then you've got an incongruous interaction that you need to worry about.

Re: Zig's New Async I/O

#223

I wrote a simple ssh server in zig to learn the language in my spare time. The new design makes the event loop / io much easier to reason about. Thanks Andy

> The new design makes the event loop / io much easier to reason about.

Interesting. How so?

Re: Zig's New Async I/O

#224

Note that this same concept is "sans io" and was previously discussed for it's use in Rust: https://www.firezone.dev/blog/sans-io https://sans-io.readthedocs.io/ https://news.ycombinator.com/item?id=40872020

If the functions are still calling I/O methods directly rather than the I/O being externally driven, I don't think that qualifies as sans-io, based on my previous exposure / based on your second link:

> For byte-stream based protocols, the protocol implementation can use a single input buffer and a single output buffer. For input (that is, receiving data from the network), the calling code is responsible for delivering code to the implementation via a single input (often via a method called receive_bytes, or something similar). The implementation will then append these bytes to its internal byte buffer. At this point, it can choose to either eagerly process those bytes, or do so lazily at the behest of the calling code.

> When it comes to generating output, a byte-stream based protocol has two options. It can either write its bytes to an internal buffer and provide an API for extracting bytes from that buffer, as done by hyper-h2, or it can return bytes directly when the calling code triggers events (more on this later), as done by h11. The distinction between these two choices is not enormously important, as one can easily be transformed into the other, but using an internal byte buffer is recommended if it is possible that the act of receiving input bytes can cause output bytes to be produced: that is, if the protocol implementation sometimes automatically responds to the peer without user input.

Re: Zig's New Async I/O

#225
post #29

Earlier quoted context omitted.

Well, it's not really a joke. That's a valid strategy that languages use. In Go, every function is "async". And it basically blocks you from doing FFI (or at least it used to?). I wonder if Zig will run into similar issues here. > 1. Code can't be reused because the async keyword statically colors a function This is fair. And it's also a real pain point with Rust. However, it's funny that the "What color is your func…

I should have specified that better, of course async and await can be lowered to different things (that's what Zig does afterall), what I wanted to say is that that's how it works in general. JS is a good counter example, but for all other mainstream languages, async means stackless coroutines (python, ruby, c#, rust, ...). Which means that if I want to use a dependency that uses async await, it's stackless coroutine…

In ruby async is based on stackful fibers. With https://github.com/socketry/async-debug you can see a tree of all fibers with their full call stack. It also avoids the problem people talk about in this thread with go of passing a context parameter everywhere for cancellation as you can kill or raise any exception inside another fiber. I haven't used them but PHP fibers are also supposedly stackful. And Java and every JVM language has them since project loom in JDK 21.

Re: Zig's New Async I/O

#226
post #225

Earlier quoted context omitted.

I should have specified that better, of course async and await can be lowered to different things (that's what Zig does afterall), what I wanted to say is that that's how it works in general. JS is a good counter example, but for all other mainstream languages, async means stackless coroutines (python, ruby, c#, rust, ...). Which means that if I want to use a dependency that uses async await, it's stackless coroutine…

In ruby async is based on stackful fibers. With https://github.com/socketry/async-debug you can see a tree of all fibers with their full call stack. It also avoids the problem people talk about in this thread with go of passing a context parameter everywhere for cancellation as you can kill or raise any exception inside another fiber. I haven't used them but PHP fibers are also supposedly stackful. And Java and every…

My mistake, I should have said Python then.

Re: Zig's New Async I/O

#227
post #144
post #30

Earlier quoted context omitted.

You’re allowed to not like it, but that doesn’t change that your argument that this is a form of coloring is objectively false. I’m not sure what Rust has to do with it.

It's funny, but I do actually like it. It's just that it walks like a duck, swims like a duck and quacks like a duck. I don't have a problem with IO conceptually (but I do have a problem with Zig ergonomics, allocator included). I do have a problem with claiming you defeated function coloring. Like, look. You didn't even get rid of await ... > try a_future.await(io);

I do want to say that I regretted that comment as nonconstructive after it was too late to edit it. Others in the thread are representing my argument better than I can or care to.

Re: Zig's New Async I/O

#228
post #219
post #194

Earlier quoted context omitted.

The problem is when C calls expect to be on a particular thread. Either the main event thread, in a GUI context, or the same thread as some related previous call.

The problem is that C expects to have enough stack to put stuff there, but green threads allocate small stacks to reduce (virtual) memory use.

That’s not a problem when a dedicated thread pool is used as mentioned by GP. However they don’t solve the thread affinity issue.

Re: Zig's New Async I/O

#229
post #68
post #11

Earlier quoted context omitted.

I'm not sure how you got the perception that we're going "all in" on green threads, given that the article in OP explicitly mentions that we're hoping to have an implementation based on stackless coroutines, based on this Zig language proposal: https://github.com/ziglang/zig/issues/23446 Performance matters; we're not planning to forget that. If fibers turn out to have unacceptable performance characteristics, then t…

That is lovely to hear. I think the general conscious is that not a single programming language has done Async right. So people are a little sceptical. But Andrew and the team so far seems to have the do it right mentality. So I guess people should be a little more optimistic. Cant wait for 0.15 coming out soon.

What is wrong with async in JS?

Re: Zig's New Async I/O

#230

Earlier quoted context omitted.

I thought it was the exact same; an event loop in Python is just whatever Io is in Zig, make it a param, get it from an import and a lookup (`import asyncio; loop = asyncio.get_running_loop()`). I might be misunderstanding what you're saying though.

hm maybe. i guess ive only used python in situations where it injects it into amain so i could have been confused. i thought python async was a wrapper around generators, and so the mechanism cant be instantiated in multiple places. i stand corrected.

Oh no you're right it's a pain in the ass and weird. But I think it's the way because there's no good reason to have more than one event loop.

Also... maybe it started out as generator wrappers? I think I read something that said that.

Post reply on HN