6 ms·
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 sto
by jerf 3y ago
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 only option for the weak runtime that it had to work with. It was the only choice.
But the Node marketing machine rumbled into action and made bold claims about performance and quality and phrased them in universals across all languages rather than merely claiming it was good for Javascript and that propaganda is still running around in people's minds to this day.
I know Rust chose it for performance reasons but I still think in a decade or two community consensus will be either that the 5% performance overhead is worth it for any non-trivial program because async is just too much worse, or someone will come up with an even lower impact version of some other option that will dominate it.
As your message demonstrates, we're still in the phase where you have to pay lip service to the supposed community consensus before saying "but I think it isn't really working out", but as I don't care about the community consensus I don't mind just saying it. Async is a mistake. It's just you manually doing what the compiler ought to be doing for you, and while I'm open to other possibilities in the future, right now threaded code is straight-up a better option on almost every metric, and the metrics where it may have a slight disadvantage, it's only slight and worth it. It's not like you choose threading and you instantly lose 10x performance or something. The first and second derivative opinions about async are clearly negative and I don't mind jumping farther ahead in the process when it comes to my own engineering decisions.
- seanhunter 3y agoAsync in its current incarnation did not come from node. Eg Haskell had async/await in 1999. https://softwareengineering.stackexchange.com/questions/377464/who-did-async-await-first https://softwareengineering.stackexchange.com/questions/3774... Node wasn't released until 10 years later.
- geodel 3y agoHow popular is Node compared to Haskell. 10 times? 100 times 1000 times? . So Node marketing machine sounds about right to me.
- jerf 3y agoAnd 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 everyone using them exclaim in joy "Yes! This is what all concurrent programming should be!" A few, sure, but far from everyone. They're kind of a bear, even after years of polish. Not only did those libraries already know about callback hell, they had already implemented some of the (partial) solutions to it. Watching the Node propaganda was almost surreal to me because I could and more-or-less did predict how it would go, years in advance, as it recreated the experience already had by other languages. Experience that did not leave the impression that this was the paradigm for the future. These libraries typically languished within their ecosystems, kept around only because they were the only practical way to, say, keep your Python but also get concurrency. The fact they were the only way to proceed kept them alive, but they never really flourished despite being right there, readily available. Node is the reason people are running around today claiming async is the bee's knees. Node is the reason why people come on to /r/golang asking how Go can possibly be used for network programming when it lacks the Magic of Async. Contradicting the Node propaganda is why people are nervous about saying "uhmm, hey, I'm using async in a big program and it's not exactly sunshine and rainbows". Prior to Node that would have just been the common understanding; these libraries were often viewed as powerful within their target language because there was no other way to do what they did, but tricky and complex to work with. It was well understood they easily degraded into a mess and were often difficult to onboard a new developer because of the difficulty of following the control flow. All I'm really saying here is, the community opinion was correct before Node and we should just go back to that opinion, founded on decades of experience.
- surajrmal 3y ago
- kibwen 3y ago> 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 whole point of Rust is that it doesn't force you to use any given paradigm when it comes to concurrency/parallelism, and has support for many approaches.
- jerf 3y agoSee other post about why I blame node. As for Rust supporting threads... yes! Yes it does! And it effectively solves all of the problems with them that can be solved at the programming language level. There's an irreducible increase in complexity with concurrent code, but there's only so much to be done about that. I think a lot of developers have a tendency to massively overprivilege performance and always reach for the biggest, shiniest thing when they don't need it, and cost themselves a lot in the process. Sure, if you're doing tens of millions of things concurrently in Rust you may need the async support because threads can't do what you want. But before you write code based on the assumption that you're going to be doing tens of millions of concurrent things on a 64-core system, check that you actually are. If you've got an API server whose request rate is measured in tens per second, a really quite common case, you'll never notice the thread overhead. You really need quite a massive system nowadays to get to the point where that's even remotely a problem, let alone your biggest one. I don't deny that when you are nailed to the wall and seriously wondering if 64 cores is going to be enough you may have specialized needs that require specialized solutions. I am glad that Rust has the option for those who need it. But async should be counted as a cost of such problems, not a benefit, and something you prove out as the only solution, not the first thing reached for.
- pjmlp 3y agoIt is the mindset that makes one buy a SLR, when they can't even make up all the options on the smartphone camera.
- 3y ago
- cmrdporcupine 3y agoWe 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 benefits. I'm sure there's a way to make it play well with Rust async and tokio, etc. but they're not really the same model on the surface. And so having bolted async into the language syntax itself, and also adding an explicit requirement on concepts like 'executors' into the language, we've created a legacy problem. IMHO async in Rust was a mistake. A systems programming language should not have mandated a technique like this, and should have stayed agnostic.
- kibwen 3y ago> A systems programming language should not have mandated a technique like this Rust doesn't mandate anything. It's unipinionated when it comes to concurrency; use whatever approach that you think is best. Async/await is just one option among many.
- cmrdporcupine 3y agoIts presence as a fundamental syntactical element is a fairly strong statement about its advisability.
- dwaite 3y agoIts presence is not a mandate. It is not a decorative syntactical element, but affects compiler code generation the same way as rust has _synchronous_ generators. A developer is still free to spawn a thousand foot-guns, and I daresay the assumption would be that they made that choice knowing how to properly juggle them.
- insanitybit 3y agoI think this is just a common misconception of io_uring based on its earlier implementations. io_uring natively supports a polling model.
- insanitybit 3y agoSaying that Rust chose async because node did is such an absurdly ignorant, incorrect statement.
- jerf 3y agoRust didn't choose async because of Node. Async's massive popularity is because of Node. It existed long before then, and that's precisely part of my point. It had a bad reputation before then, and it's slowly-but-surely reacquiring it now.
- insanitybit 3y agoRust didn't choose async because it was popular. You can go ahead and read the massive, multi-year discussions on the topic if you'd like. They've been going on since before 1.0.
- twic 3y agoI read them at the time. The gist was basically "it has been empirically established that async is the right way to do concurrency" - ie, it was because of Node.
- insanitybit 3y agoThat's nonsense
- vacuity 3y agoIt was more "it fits best with our needs as a systems language (overloaded term, yada yada) and we should support a robust concurrency model sooner rather than later". The Rust devs were aware of green threads and the like. It is deeply unfortunate that async is still such a mess, though.
- iopq 3y agoThey specifically referred to C# and its efficient implementation
- ahupp 3y agoI used/worked on a similar async model at FB long before I'd ever touched node. Threads are not really solving the same problem as async. Imagine you are building the FB newsfeed. You have 10 stories and want to fetch them as quickly as possible. The stories are all different types and each refers to other data: profile info, privacy, comments (which depend its own profile fetch), likes, etc. So you have this tree of dependent data fetches, how do you minimize the time waiting? You could walk the tree node-by-node, but that balloons your wait time. So you kick each bit of work off to a new thread and wait for it to be done. How do you wait for it? Lots of options of course, but they all end up looking like an ad-hoc implementation of async. Which is fine! But if you have a large codebase where a large fraction of code is dealing with this stuff you pretty soon want the runtime to handle this. And if you are mixing code written by others you really want everyone to use the same mechanism. So the value of async isn't really in the specific implementation choices, it's that it lets you represent this tree in a consistent way. This is less about the number of requests per second, and more about how much code you have to deal with; plenty of places have low RPS but have accumulated lots and lots of code. Second, threads have their own costs even ignoring performance. Arguably a big reason PHP/Hack worked so well for FB is that each request was single-threaded and started with a clean state; there's whole universes of bugs that are avoided in this model. And node doesn't have threads because JS doesn't have threads, microcontrollers may not have threads, etc.
- jerf 3y agoI 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 it is conceived of today was a hack for dynamic scripting languages that basically had no other option. They "won" there because the environments simply couldn't support any other solution, not because they outcompeted anything.
- osmarks 3y ago
- pdimitar 3y agoI 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.