Live data from Hacker News

Local async executors and why they should be the default

maciej.codes

201–210 of 327 posts

Re: Local async executors and why they should be the default

#201
post #155

Earlier quoted context omitted.

I used "async" long before Node too. It's one of the reasons I knew to stay away from Node. "ad-hoc implementation of async" I think you're confusing the problem with the solution. I solve this sort of thing in Go all the time. This is literally what I was doing yesterday. It's fine in that context. You had to reach for async because it was the only option in your context, not because it was the best choice. Async as…

Go is internally doing async-like cooperative multitasking. You just don't see it because they actually integrated it into the language well.

As jerf said in a parent comment,

> It's just you manually doing what the compiler ought to be doing for you,

Re: Local async executors and why they should be the default

#202
post #113

Just a personal take: after not coding with Rust for several months, I find it more and more difficult to return to an async code I was writing. The whole thing just reads... ugly and inconsistent. It needs too much already-accumulated knowledge. As the article correctly points out, you need a bunch of stuff that are seemingly unrelated (and syntactically speaking you would never guess they belong together). And as o…

I really think in the end, in another decade or two, the community consensus is going to be that async as it is conceived of today is simply a mistake, full stop. Think about it. Where did it come from in its current incarnation? Node. Why did Node choose it? Did it have a multiplicity of options and carefully choose the best one based on years of experience with each choice? No. Async was "chosen" because it was the…

I am not versed in computer science well enough to comment on the model in general but I'll agree that the current way of doing async is pretty sloppy. When you fully invest your project in it and use async libraries it does get better but some compilation errors still sound like dark magic (I'll forever regret not writing down a few of them I encountered last year because the team is receptive to changing rustc error message).

Though I'll also say plain old multithreading and async are serving different niches, in my experience.

Re: Local async executors and why they should be the default

#203
post #167
post #125

Earlier quoted context omitted.

> Where did it come from in its current incarnation? Node. Rust's async/await is inspired by C# (which was inspired by F#, which was inspired by Haskell). > right now threaded code is straight-up a better option on almost every metric, Agreed that people are generally too eager to reach for async when they could easily get away with threads, and fortunately Rust makes threads extremely pleasant to work with. The whol…

And yet it didn't learn that it took almost 10 years for .NET community to sort out async/await support across all layers of the stack. .NET archictects have spent last year researching Go and Java Loom approaches, and have acknowledge if it had been today, most likely that would have been the approach taken instead of async/await, as many .NET devs still get it wrong. During the "ASP.NET Core and Blazor futures, Q&A…

Everyone rediscovers Erlang at one point in this space, it seems.

Re: Local async executors and why they should be the default

#204
post #142

Earlier quoted context omitted.

And I have code still in production written in the "Perl Object Environment", one of several async frameworks for Perl, written before Node even existed. Also before Node existed, I had written code in the Twisted framework for Python. Node did not invent async by any means and I know it in the strongest possible sense, having used it before Node existed. But those libraries, in use for over a decade, did not make ev…

Async await isn't useful because it's more ergonomic. It's useful because it's low overhead. If you don't care about that then rust might not be the right language for you the same way a language with a GC might be better suited for most folks. For my domain, any other choice would have made rust untenable. Rust has made all the right choices that make it an excellent choice for code I was otherwise forced to use c o…

IMO almost nobody demands a language to "bend its way" so as to not "make folks upset", it's just that the way Rust went about async/await is not ergonomic at all. It's also pretty dark, as in it's hard to surface good information.

Re: Local async executors and why they should be the default

#205

Earlier quoted context omitted.

> but I'd rather do that than try to figure out how to get some dependency that isnt meant to use async to work in some async move closure tokio::spawn_blocking [1], see it's not that hard. But sure to use another language you must learn it, an it requires a bit if effort… [1] assuming you want to use tokio like post people do, but other executors should have the same kind of functions to do that as well if need be.

You've made the giant assumption that most people working in Rust are working with some kind of executor or framework, and you're either wrong, or the state of the Rust world has become very depressing. tokio::spawn_blocking doesn't exist in my codebase because I'm not using tokio, nor should I have to in order to use library code from a crate. This is the problem with async in a nutshell; it's viral, and it brings w…

> tokio::spawn_blocking doesn't exist in my codebase because I'm not using tokio, nor should I have to in order to use library code from a crate.

If you're trying to use a library that uses Futures, then you need an executor to poll that futures to completion. But then it's not the same situation as the one I'm responding to (where it was about using blocking code in an async context).

If you have blocking code and need a way to poll third-party futures to completion then it's tokio::block_on or equivalent that you need.

> This is the problem with async in a nutshell; it's viral

That's the biggest misunderstanding about async/await: it's not async that's viral, it's IO. If your library does IO, then you do IO and have to deal with the fact. And you have to actively deal with it no matter what, because IO is slow and you definitely do not want your UI thread be frozen[1] because something under the hood is doing IO. The only difference is that async makes it explicit in the typesystem, where blocking does not and you need to guess where to spawn new threads.

[1] or your thread that's listening on incomming sockets.

Re: Local async executors and why they should be the default

#206

Earlier quoted context omitted.

And then people are saying that their microservice is high performance because it's handling 10 000 req/s per 72 core node... which is ok but rather per core (depending on the amount and type of logic being processed), not node. I'm handling requests in high microseconds range (median) in high volume, low latency network service with hard limits on latency numbers (not HFT). Good luck building that kind of service (a…

Any design pattern can be applied in a wrong way.

Sure it can, but all design patterns have their use cases. Generalizing and saying that one is just "terrible" (which your previous comment implied), and people "should learn" is just untrue and an ignorant take. Sometimes it's the only sane solution compared to others, considering project constraints.

Re: Local async executors and why they should be the default

#207
post #93

Earlier quoted context omitted.

> but I'd rather do that than try to figure out how to get some dependency that isnt meant to use async to work in some async move closure tokio::spawn_blocking [1], see it's not that hard. But sure to use another language you must learn it, an it requires a bit if effort… [1] assuming you want to use tokio like post people do, but other executors should have the same kind of functions to do that as well if need be.

It's not always that simple. What if your sync lib has some callbacks, and you want to do something in the callbacks that requires async. You could argue that this mismatch exists even with rust itself, where you have Drop, which is sync, and you might have to do something in your drop that requires async, like closing a network connection. You have to pass in some runtime handle that you can use to spawn a task to d…

Within your sync callback spawned via spawn_blocking, you can run async code with Handle::current().block_on(…): https://docs.rs/tokio/latest/tokio/runtime/struct.Handle.htm....

Re: Local async executors and why they should be the default

#208

Earlier quoted context omitted.

We wrote asynchronous driven network code for decades without syntactic sugar for it, and it was fine. That 5% performance gain can be had without it. Async syntax is a mistake. Not just because of the mess it makes across the program tree, but also because it brings with it a specific notion of how to do asynchronous I/O. io_uring for example gives an entirely different model, one with some lovely performance benefi…

Having written decades of async code without rust (and still doing so in c++), I don't understand your point. It is really hard to write safe highly performant asynchronous code. Rust makes it safe, but without the additional "syntax sugar" it makes it very unergonomic. The developer velocity I can achieve with async rust is unbelievable compared to what I had to do previously. I think your problem may be with tokio,…

> The developer velocity I can achieve with async rust is unbelievable compared to what I had to do previously.

I have seen a glimpse of that in my paid work but I have to say it takes quite a while and a lot of nerves expended to get to that point. It's one of these things where you climb a mountain peak and can now see everything clearly but before that it's all a mess, mists and shadowy figures.

Re: Local async executors and why they should be the default

#209
post #118

Earlier quoted context omitted.

> now there is a MVP syntax and everything has just slowed down a lot. Sadly this is spot on. Seems like after async was delivered there was only one big push from tokio 0.1 to 0.2 to 1.0 and that was it, the ecosystem and/or language maintainers seem to have lost interest in making it better to read and use.

Nobody has lost interest, the language maintainers have been pushing on this problem for years. Scroll back through Niko's blog posts and see how many of them are related to improving async: https://smallcultfollowing.com/babysteps/ The reason that progress appears slow is because the next steps for async improvement have required extending the type system, and doing that properly (making sure not to introduce unsoun…

I see, thank you for the clarification. Shame that it takes so long. I really need Rust's async benefits without all the baggage and the 6 months trial-by-fire training that it requires, and I need them right now, but it seems I'll be using other languages for the moment, and just scale infrastructure. Which is a real shame because Rust did make many good calls.

Re: Local async executors and why they should be the default

#210

Earlier quoted context omitted.

The fun part is over. At least that is how a rust maintainer described it to me. When I asked why doing the unfun part (documentation, maintenance, etc.) isn't a condition for allowing people to do the fun part (pushing cool new code), it got no response.

Because open-source projects survive on people having fun improving them. There just isn't that many people working on the Rust language as a day job, and they all have their hands full. Some of them have been working on foundational stuff that is required to get async rust to work, but it's work taking place over years. To give an example, the Inside Rust blog recently posted [1] an article about the Rust Trait Syst…

While I commend the effort, I am not sure that an even more complex lifetime syntax is what the Rust devs wanted... We'll see then.
Post reply on HN