Live data from Hacker News

Async/Await is finally back in Zig

charlesfonseca.substack.com

81–90 of 90 posts

Re: Async/Await is finally back in Zig

#81
post #13

Someone has historical insights into why async/await seems to have taken over the world? I often write Rust and I don't find it very attractive, but so many good projects seem to advertise it as a "killer feature". Diesel.rs doesn't have async, and they claim that perf improvement may not be worth it ( https://users.rust-lang.org/t/why-use-diesel-when-its-not-as... ). For a single threaded JS program, async makes a l…

The classic use case for async was applications with extreme I/O intensity, like high-end database engines. If designed correctly it is qualitatively higher performance than classic multithreading. This is the origin of async style. Those large performance gains do not actually come from async style per se, which is where people become confused. What proper async style allows that multithreading does not is that you…

> The classic use case for async was applications with extreme I/O intensity, like high-end database engines. If designed correctly it is qualitatively higher performance than classic multithreading.

FWIW, I'm not aware of any high end database engines that make significant use of async code on their performance paths. They manage concurrent state with event loops, state machines, and callbacks. Those techniques, while crufty and too old to be cool, are themselves significantly faster than async.

Async code (which is isomorphic to process-managed green threads) really isn't fast. It's just that OS thread switching is slow.

Re: Async/Await is finally back in Zig

#82
post #75
post #73

Earlier quoted context omitted.

That's a different type of overhead than having unwind tables. With exceptions you wouldn't need a branch after each function call at all.

But a branch that is (almost) never taken has an overhead close to the overhead of a NOP instruction, which may be negligible on modern architectures.

The CPU can not remember an infinite number of branches. Also, many branches will increase code size. With exceptions the unwind tables and unwind code can be placed elsewhere and not take up valuable L1 cache.

Re: Async/Await is finally back in Zig

#83
post #82
post #75

Earlier quoted context omitted.

But a branch that is (almost) never taken has an overhead close to the overhead of a NOP instruction, which may be negligible on modern architectures.

The CPU can not remember an infinite number of branches. Also, many branches will increase code size. With exceptions the unwind tables and unwind code can be placed elsewhere and not take up valuable L1 cache.

> The CPU can not remember an infinite number of branches.

I suspect a modern CPU has a branch instruction saying "This branch will never be taken except in exceptions, so assume this branch is not taken". But I must admit I haven't seriously looked at assembly language for some time.

(EDIT: yes, modern CPUs including x86 and ARM allow the programmer/compiler to hint if a branch is expected to be taken).

> Also, many branches will increase code size.

I'd like to see some data on that. Of course branches take code size, but how much is that percentage-wise? I suspect not much.

Re: Async/Await is finally back in Zig

#84
post #83
post #82

Earlier quoted context omitted.

The CPU can not remember an infinite number of branches. Also, many branches will increase code size. With exceptions the unwind tables and unwind code can be placed elsewhere and not take up valuable L1 cache.

> The CPU can not remember an infinite number of branches. I suspect a modern CPU has a branch instruction saying "This branch will never be taken except in exceptions, so assume this branch is not taken". But I must admit I haven't seriously looked at assembly language for some time. (EDIT: yes, modern CPUs including x86 and ARM allow the programmer/compiler to hint if a branch is expected to be taken). > Also, many…

You should take a look at the presentation I mentioned elsewhere in this thread. You also have to keep in mind that it's not only the branches that use space, but also the error handling code. Code which must be duplicated for every single call to a particular function.

Re: Async/Await is finally back in Zig

#85

Earlier quoted context omitted.

> If you use async I/O you can just use the Chrome JavaScript runtime as-is. What do you mean? A JS runtime can't do anything useful on its own, it can't read files, it can't load dependencies because it doesn't know anything about "node_modules", it can't open sockets or talk to the world in any other way - that's what Node.js provides. > I would claim it was the only low-effort model available to them and therefore…

Obviously you can add modules calling to C/C++ functionality to a scripting language runtime easily (and the interface to do that is already available for the browser implementation). In the above link Node could be described as a Chrome V8 distribution with modules enabling building a web server. Adding threading to a non-threaded scripting runtime is another ball game. The point is that Node was forced into this mo…

> Obviously you can add modules calling to C/C++ functionality to a scripting language runtime easily

Yes, obviously, that's what NodeJS does. But you can't "just use the V8 runtime as-is if you're doing async IO", it doesn't have those facilities at all.

Async IO wasn't just "sold as an advantage", it is an advantage. Websockets were gaining popularity around that time and async IO is a natural fit for that.

You would have to change the language and boil the ocean to make the runtime support multiple threads (properly).

But why? Just to end up with the inferior thread-per-request runtime (which by the way, still needs to support async because it's part of the language), that requires developers to write JS which is incompatible with browser JS, which would've eliminated most of the synergy between the two?

I really don't understand what you're going for here. I don't see a single advantage here.

Re: Async/Await is finally back in Zig

#86
post #84
post #83

Earlier quoted context omitted.

> The CPU can not remember an infinite number of branches. I suspect a modern CPU has a branch instruction saying "This branch will never be taken except in exceptions, so assume this branch is not taken". But I must admit I haven't seriously looked at assembly language for some time. (EDIT: yes, modern CPUs including x86 and ARM allow the programmer/compiler to hint if a branch is expected to be taken). > Also, many…

You should take a look at the presentation I mentioned elsewhere in this thread. You also have to keep in mind that it's not only the branches that use space, but also the error handling code. Code which must be duplicated for every single call to a particular function.

Ok, thanks. But that code needs to be loaded into memory only if the branch takes place. Which, for exceptions, will be not often. The main assumption is: optimize for the common case, where exceptions are not the common case.

Re: Async/Await is finally back in Zig

#87
post #51

Earlier quoted context omitted.

This is like saying knowing if you're dealing with NEAR pointers or FAR pointers is extremely relevant. I reject the premise - a model that forces me to think about these things is a degenerate model.

That's fine but the alternatives are insufficient.

Obviously "insufficient" is always going to be subjective. But some technologies really do end up bad by consensus, and I'm getting that smell from async. There really aren't any world class software efforts that rely heavily on async code. Big projects that do end up complaining about maintenance and cognitive hassle, and (c.f. the futurelock thing) are starting to show the strains we saw with C++ exceptions back in the day.

Async looks great in a blog post full of clean examples. It... kinda doesn't in four year old code written by people who've left the project.

Re: Async/Await is finally back in Zig

#88

Earlier quoted context omitted.

Obviously you can add modules calling to C/C++ functionality to a scripting language runtime easily (and the interface to do that is already available for the browser implementation). In the above link Node could be described as a Chrome V8 distribution with modules enabling building a web server. Adding threading to a non-threaded scripting runtime is another ball game. The point is that Node was forced into this mo…

> Obviously you can add modules calling to C/C++ functionality to a scripting language runtime easily Yes, obviously, that's what NodeJS does. But you can't "just use the V8 runtime as-is if you're doing async IO", it doesn't have those facilities at all. Async IO wasn't just "sold as an advantage", it is an advantage. Websockets were gaining popularity around that time and async IO is a natural fit for that. You wou…

I think green threads (Java Virtual Threads, Go to an extent) are strictly superior to async/await.

If you don't have many threads, OS threads are okay as well. It is all about memory and scheduling overhead.

But that is just my opinion. You are welcome to have a different opinion.

Re: Async/Await is finally back in Zig

#89

Async/await feels very misguided to me. It's an extremely complex language feature for something that can be done way better, completely in userspace. You can implement stackful coroutines yourself in C/C++, you need like 30 lines of assembly (as you can't switch stack pointers and save registers onto the stack from most languages). This is WAY better than what you could do for example with the way more convoluted C+…

Zig's implementation is in userspace.

Re: Async/Await is finally back in Zig

#90

Earlier quoted context omitted.

> Obviously you can add modules calling to C/C++ functionality to a scripting language runtime easily Yes, obviously, that's what NodeJS does. But you can't "just use the V8 runtime as-is if you're doing async IO", it doesn't have those facilities at all. Async IO wasn't just "sold as an advantage", it is an advantage. Websockets were gaining popularity around that time and async IO is a natural fit for that. You wou…

I think green threads (Java Virtual Threads, Go to an extent) are strictly superior to async/await. If you don't have many threads, OS threads are okay as well. It is all about memory and scheduling overhead. But that is just my opinion. You are welcome to have a different opinion.

No I don't think your opinion is "wrong" or anything, it's just that this is a language-level limitation and not a valid criticism of NodeJS.
Post reply on HN