29 ms·
Async-await on stable Rust
- GolDDranks 7y agoThis is big! Turns out that syntactic support for asynchronous programming in Rust isn't just syntactic: it enables the compiler to reason about the lifetimes in asynchronous code in a way that wasn't possible to implement in libraries. The end result of having async/await syntax is that async code reads just like normal Rust, which definitely wasn't the case before. This is a huge improvement in usability.
- takeda 7y agoWhy would it be different for async code than sync code? The goal of Rust's checker is to track lifetime of an object so for example it knows that at the end of a function the object should be freed. Async shouldn't matter here.
- aliceryhl 7y agoIn Rust, it is normally not possible or at least very difficult to create structs where one field references another, and if you were to create a future that borrows some field, awaits a future, and uses the borrowed field, the resulting future will need to have a field with a reference to another. This is the challenge and async await lets you make this kind of self referential types without unsafe code.
- antisemiotic 7y agoThat's just the "Pin" type, which is heavily used in async code behind (and occasionally in front) the scenes, but is by no means restricted to it.
- Nemo157 7y agoIt's impossible to use the guarantees provided by the `Pin` type without `unsafe` code, except in `async fn`.
- GolDDranks 7y agoThe point is that Rust's borrow checker can't reason about lifetimes very well over function boundaries. It can reason about coarse things that are expressable in the type language, but everything more nuanced than that, such as reasoning about how control flow affects the lifetimes is limited to inside function bodies. The difference between synchronous code and async code implemented as libraries is that async code involves jumping in and out of functions a lot, while employing runtime library code in between. A piece of code that is conceptually straightforward, may, in the async case, involve multiple returns and restores. In the sync case it doesn't need to do that, since it just blocks the thread and does the processing in other threads and in kernel land. Rust's async/await support makes it possible to write code that is structurally "straightforward" in a similar way than synchronous code would be. That allows the borrow checker to reason about it in a similar way it would reason about sync code.
- asdkhadsj 7y agoIf you're familiar with this, can you describe some of those new concepts in ... slightly more detail? I say slightly, because I'm still seeking high level explanations, but at the same time I'm curious what new features might be making this async lifetime talk possible. To further frame that question: I had assumed Rust was implementing Async within the capabilities of normal Rust. Such that, if lifetimes were being managed across function bounds, I assumed the lifetime would have "simply" been bound to the scope of the executor, polling the future you're actively waiting on. However quickly I can see confusions in that description. Normal lifetimes within a function would need to bubble up and be managed by a parent, since that function's lifetime is, as you put it, being jumped in and out of frequently. So I imagine that is partly where new features come into play? Giving Rust the ability to take a normal lifetime and extend or manage it in new ways?
- GolDDranks 7y agoI'm not going to elaborate super deeply in a HN comment, but here's the gist: inside a function body, you can take a reference to a thing, and store that reference in a variable. Then if that function were "yields" to the executor, we have a situation that we couldn't have with sync code: in sync code, the "yielding" only happens at the function return, and by that point, all the internal references must be gone, as the function stack frame is going to disappear. But with async, as the yielding can happen without the function actually ending, we have to be able to store the stack frame, and the references stay alive. The new feature helps the compiler to reason about this. Before the "yields" were implemented as just returns, so the compiler didn't allow borrowing over yield points.
- epage 7y agoThe challenge with async code is that the state across yield points is put into a struct and if a reference to a stack variable is used across yield points, then that struct is self-referential which Rust can't reason about (yet?). I honestly do not know who much can be recreated with `unsafe` and `Pin` vs how much is built-in. I'd love for Rust to eventually get a Move trait (something like C=+ move constructors) to resolve this. Besides some complexity in designing it, there is resistance from some corners about having anything execute on a move.
- stbuehler 7y agoThat is exactly what `async` blocks are about: they do support self-referential structs, and `Pin` is what allows us to use those in a safe way, as `Pin`ned data can't be moved again (unless the data is `Unpin`, which self-referential structs are not), so the self-references are safe.
- golergka 7y agoThis is great news! I tried out Rust for a typical server-side app over a year ago (JSON API and PostgreSQL backend), and the lack of async-await was the main reason I switched back to Typescript afterwards, even though Diesel is probably the best ORM I've ever worked with. Time to give it a try again.
- sudeepj 7y agoThis is going to open the flood gates. I am sure lot of people were just waiting for this moment for Rust adoption. I for one was definitely in this boat. Also, this has all the goodness: open-source, high quality engineering, design in open, large contributors to a complex piece of software. Truly inspiring!
- ChrisSD 7y agoAre there that many people looking for a new low level language for server side software?
- sudeepj 7y agoI think so. Off-course this is my belief and based on different opinions/experiences shared by people over last 3-4 years.
- nicoburns 7y agoRust isn't only great because it's low level. Things like sum types (called enums in rust), pattern matching and expression orientation mean that it is often much more expressive than other languages for high level code.
- umanwizard 7y agoML-inspired languages have all these features too; is the advantage of Rust over those just that it’s more mainstream, the ecosystem is bigger, etc.?
- nicoburns 7y agoThat, and that it has better support for imperative features than most ML languages. You can combine your fancy combinators with mutable variables and for-loops when just want to get something done quickly. In general, Rust just has all the little details right. It's hard to describe that in concrete terms, but it makes using it a very smooth and satisfying process. I get a similar feeling when using postgres: there's usually a nice way of doing what I want, and I rarely come up against unwelcome surprises.
- trpc 7y agoThank you Alex Crichton, Niko Matsakis and all other core devs, Rust is by far the most well designed programming language I've ever dealt with. It's a masterpiece of software engineering IMO.
- bullen 7y agoHow does rust perform in parallel on the same memory? I heard it uses locks? This is not on the same memory right? https://news.ycombinator.com/item?id=21469295 https://news.ycombinator.com/item?id=21469295 If you want to do joint (on the same memory) parallel HTTP with Java I have a stable solution for you: https://github.com/tinspin/rupy https://github.com/tinspin/rupy
- asdkhadsj 7y agoThe same as any language, if you were to write safe code at least. By safe code I mean, if you wrote Go in such a way that race conditions could not happen, you typically would write it in the same way in Rust. Often this involves Mutexes, but there are plenty of libraries that set up foundations for parallel behavior without Mutexes. So it can operate on "the same memory", and there are a whole lot of ways to manage it safely. The right tool for the right job, really.
- whb07 7y agothis isn't quite right, this feels like what the standard response from a developer with some hubris. Humans are fallible and mushy, and depending on their current state are error prone. So why not just codify some "best practices" that are built in as primitives to a language like Rust? There are ways to perform parallel work that is "safe", Rust solves this with the borrow/checker implementation, another clear "safe" way would be to make everything immutable as seen on Haskell, Ocaml, F# to where who cares about who gets to what first if the underlying thing will never change. Mutexes and locks and all the other ways of doing parallel work that is "safe" isn't a primitive thats cooked in with the language.
- asdkhadsj 7y agoSorry, maybe I misunderstood OP. I was responding to what I thought was a general, vague question about how something safe might work in Rust, compared to other languages (Go in my example). So while I don't think what I said was incorrect re: Go vs Rust concurrency, perhaps I misunderstood OPs question. > Mutexes and locks and all the other ways of doing parallel work that is "safe" isn't a primitive thats cooked in with the language. I didn't understand OPs question as strictly features cooked into the language, so I was not saying that. With that said, if you're not allowing for Mutexes for "safe things that are cooked into the language" I feel like you won't like Rust. This is an odd metric, though. edit: words
- kodablah 7y agoI've been working with alpha futures, tokio, hyper, etc with async/await support on rust beta (didn't use async std yet) and can attest to them working quite well. There was quite a learning curve for me to know when to use arc, mutex, different stream combinators, and understand raw polling, but after I did, writing the code became a bit easier. I suggest anyone wanting to learn to grab a tcp-level networking project/idea/protocol and grind on it for days, heh.
- aashcan 7y agoCould you share some resources? I'm trying to move a Hyper + Tokio-core + Futures project to the newer versions and am struggling..
- kodablah 7y agoI don't really have any except to use the alphas of tokio and toy with it. The tokio alpha docs and the async book[0] has some info, but both are a bit incomplete. 0 - https://rust-lang.github.io/async-book/ https://rust-lang.github.io/async-book/
- losvedir 7y agoExciting! I know this has been a long time coming, so congrats to everyone for finally landing it in stable. As a rust noob, small question based on the example given: Why does `another_function` have to be defined with `async fn`? Naively, I would expect that because it calls `future.await` on its own async call, that from the "outside" it doesn't seem like an async function at all. Or do you have to tag any function as async if it calls an async function, whether or not it returns a future?
- estebank 7y agoYou have to tag a function as async if interacts with anything async and doesn't create an executor itself. Executors have functionality that let you start an async fn/block in the currently instantiated executor and return immediately. Such a function wouldn't need to be marked async, IIUC. Note that marking a function as async is only syntactic sugar for a function that returns a future.
- Matthias247 7y agoEven if you don’t await anything async fns behave different. They will get compiled to a function which returns a Future. When you call the function - nothing happens. The body will only be executed when someone starts polling the Future. This will also have a big impact on all lifetimes - since they now get part of the returned Future type. Now would you tag something as async if not required? Likely not - it just makes things more complicated. One exception is when you expect you need to modify the body of the function in the Future to make use of await, and you want to maintain compatibility
- jkarneges 7y agoAn async function compiles down a function that returns an iterable-ish state machine thing (a Future), that needs to be stepped through. The await keyword indicates a yield point. It's kind of like how if you declare a Python function containing the yield keyword, then the function returns an iterable rather than simply executing top to bottom. In the same way that Python yield only makes sense from within an iterable, Rust's await keyword only makes sense inside of a Future. Outside of a Future, there'd be no concept of a yield. This is why the "outer" function must be declared async.
- brunt 7y agoLooks like someone needs to update https://areweasyncyet.rs/ https://areweasyncyet.rs/
- ComputerGuru 7y agoI’ve been playing with async await in a polar opposite vertical than its typical use case (high tps web backends) and believe this was the missing piece to further unlock great ergonomic and productivity gains for system development: embedded no_std. Async/await lets you write non-blocking, single-threaded but highly interweaved firmware/apps in allocation-free, single-threaded environments (bare-metal programming without an OS). The abstractions around stack snapshots allow seamless coroutines and I believe will make rust pretty much the easiest low-level platform to develop for.
- littlestymaar 7y agoThe Fushia team also uses Rust's async/await this way in the implementation of their network stack.
- vanderZwan 7y agoHave you ever heard of Esterel or Céu? They follow the synchronous concurrency paradigm, which apparently has specific trade-offs that give it great advantages on embedded (IIRC the memory overhead per Céu "trail" is much lower than for async threads (in the order of bytes), fibers or whatnot, but computationally it scales worse with the nr of trails). Céu is the more recent one of the two and is a research language that was designed with embedded systems in mind, with the PhD theses to show for it [2][3]. I wish other languages would adopt ideas from Céu. I have a feeling that if there was a language that supports both kinds of concurrency and allows for the GALS approach (globally asynchronous (meaning threads in this context), locally synchronous) you would have something really powerful on your hands. EDIT: Er... sorry, this may have been a bit of an inappropriate comment, shifting the focus away from the Rust celebration. I'm really happy for Rust for finally landing this! (but could you pretty please start experimenting with synchronous concurrency too? ;) ) [0] http://ceu-lang.org/ http://ceu-lang.org/ [1] https://en.wikipedia.org/wiki/Esterel https://en.wikipedia.org/wiki/Esterel [2] http://ceu-lang.org/chico/ceu_phd.pdf http://ceu-lang.org/chico/ceu_phd.pdf [3] http://sunsite.informatik.rwth-aachen.de/Publications/AIB/2018/2018-05.pdf http://sunsite.informatik.rwth-aachen.de/Publications/AIB/20...
- mamcx 7y ago
- ralusek 7y agoIsn't it kind of a poor design choice that Rust will not actually begin execution of the function until `.await` is called? If I didn't want to execute the function yet, I wouldn't have invoked it. Awaiting is a completely different concept than invoking, why overload it? If you want to defer execution of a promise until you await it, you can always do that, but this paradigm forces you to do that. The problem is then, how do I do parallel execution of asynchronous tasks? In JavaScript I could do const results = await Promise.all([ asyncTaskA(), asyncTaskB(), asyncTaskC() ]); and those will execute simultaneously and await all results. And that's me deferring execution to the point that I'd like to await it, but in JavaScript you could additionally do const results = await Promise.all([ alreadyExecutingPromiseA, alreadyExecutingPromiseB, alreadyExecutingPromiseC ]); Where I pass in the actual promises which have returned from having called the functions at some point previously. So how is parallel execution handled in Rust?
- Buttons840 7y agoAre you sure? How would the JavaScript functions execute simultaneously on a single thread? Async is about interleaving computations on a single thread.
- ilikehurdles 7y agoAsync doesn't have to be single-threaded generally. JavaScript is limited to a single-threaded model, but in other languages (like clojure), futures are tasks run on some other thread. I don't use rust and this article doesn't make any mention of threads so I'm not really sure what's going on here.
- Rusky 7y ago> futures are tasks run on some other thread. This is usually false, in Rust and elsewhere. Futures are tasks that run on whatever thread is scheduling them. They are an even lighter-weight version of green threads/fibers/M:N.
- 7y ago
- faitswulff 7y agoWill the Rust Programming Language book be updated with async/await?
- steveklabnik 7y agoAt some point, yes. Carol and I have not figured out how we want to do it.
- bora_gonul 7y agoQuick please :)
- wiineeth 7y agoIs there anyone who has used rust instead of C++? What's your opinion on it?
- Dowwie 7y agoThis is a major milestone for Rust usability and developer productivity. It was really hard to build asynchronous code until now. You had to clone objects used within futures. You had to chain asynchronous calls together. You had to bend over backwards to support conditional returns. Error messages weren't very explanatory. You had limited access to documentation and tutorials to figure everything out. It was a process of walking over hot coals before becoming productive with asynchronous Rust. Now, the story is different. Further a few heroes of the community are actively writing more educational materials to make it even easier for newcomers to become productive with async programming much faster than it took others. Refactoring legacy asynchronous code to async-await syntax offers improved readability, maintainability, functionality, and performance. It's totally worth the effort. Do your due diligence in advance, though, and ensure that your work is eligible for refactoring. Niko wasn't kidding about this being a minimum viable product.
- aashcan 7y agoAll we need are a few migration guides for Tokio, Hyper, Futures...
- fooyc 7y agoThis is a big improvement, however this is still explicit/userland asynchronous programming: If anything down the callstack is synchronous, it blocks everything. This requires every components of a program, including every dependency, to be specifically designed for this kind of concurency. Async I/O gives awesome performance, but further abstractions would make it easier and less risky to use. Designing everything around the fact that a program uses async I/O, including things that have nothing to do with I/O, is crazy. Programming languages have the power to implement concurrency patterns that offer the same kind of performances, without the hassle.
- Analemma_ 7y ago> Async I/O gives awesome performance, but further abstractions would make it easier and less risky to use. Designing everything around the fact that a program uses async I/O, including things that have nothing to do with I/O, is crazy. Microsoft kind of tried to do this with the new APIs for UWP: pretty much everything is async, the blocking versions of APIs were all eliminated, so there was no way for the async-ness to "infect" otherwise synchronous code. It was actually a pretty nice way to program; it's a shame it never took off.
- nicoburns 7y agoThe JavaScript world is pretty close to this. Not quite everything is async, but almost everything is async-first.
- Matthias247 7y agoThe javascript world was forced into this. Since it doesn't (or at least didn't) expose threads, everything had to be non-blocking. Otherwise programs would be non-responsive all the time.
- yakz 7y agoThey're finally opening the APIs (already have, I think, to some extent) for use with normal desktop apps and "UWP" apps outside of the Store. You can even embed the new UI stuff inside of Forms and WPF apps via XAML islands. They also lowered their portion of the revenue share considerably for Store apps, afaik.
- MuffinFlavored 7y agoFor JavaScript developers expecting to jump over to Rust and be productive now that async/await is stable: I'm pretty sure the state of affairs for async programming is still a bit "different" in Rust land. Don't you need to spawn async tasks into an executor, etc.? Coming from JavaScript, the built in event-loop handles all of that. In Rust, the "event loop" so to speak is typically a third party library/package, not something provided by the language/standard itself.
- steveklabnik 7y ago> I'm pretty sure the state of affairs for async programming is still a bit "different" in Rust land. There are some differences, yes. > Don't you need to spawn async tasks into an executor, etc.? Correct, though many executors have added attributes you can tack onto main that do this for you via macro magic, so it'll feel a bit closer to JS.
- adgasf 7y agoCan anyone help explain if Rust asyncs are hot (as in JavaScript, C++) or cold (as in F#)?
- steveklabnik 7y agoCold.
- rhodysurf 7y agoThey are cold
- pornel 7y agoIf you're just starting to learn Rust, I suggest waiting a little before using async. It's awesome, BUT libraries, tutorials, etc. will need a while to update from the prototype verion of Futures (AKA v0.1) to the final version (std::future). Changes made during standardization were relatively minor, but there's no point learning two versions of Futures and dealing with temporary chaos while the ecosystem switches to the final one.
- eeZah7Ux 7y agoThe level of fanboyism in the comments is saddening. Many other fast and productive languages have async since a while.
- pixel_fcker 7y agoOr maybe there are just a lot of people who like using rust because it fits their use cases very well and are excited about the release of a big new feature that’s been in development for a long time?
- kgraves 7y ago>...because it fits their use cases very well and are excited about the release of a big new feature. a bit too excited. GP isn't wrong, Go pretty much has the same thing and I have never seen so much fanboyism for a single feature ever in my career. I don't get it, but that might be because I am a manager.
- monocasa 7y agoGo's is a little different. I can't run Go on something with 2k of RAM like an Arduino, but Rust's async structure is actually extra helpful there.
- 0xdead 7y agoCan Rust's async even work on an Arduino or any bare-metal system?
- steveklabnik 7y agoYes. Right now the implementation requires TLS but that will be going away.
- monocasa 7y agoTo whoever downvoted Steve, he's talking about thread local storage, not transport level security.
- deleted 7y ago[deleted]
- overthemoon 7y agoI have honestly never enjoyed learning a language more than I've been enjoying Rust, the docs and material are so thorough and clear. Very excited to tackle this topic.
- sergiotapia 7y agoHow does Rust compare to Nim? It seems Nim is as fast as C, static binaries, and ergonomic UX. Whereas Rust looks like C++ mixed with bath salts.
- mratsim 7y agoNim dev here. If you are talking about async/await: - for concurrency it has been in the standard library for a couple of years. Also you can implement it as a library without compiler support. - for parallelism, Rust is in advance. Nim has a simple threadpool with async/await (spawn/^), it works but it needs a revamp as there is no load balancing at all. You can also fallback on the raw pthreads/windows fibers and/or OpenMp for your needs or even OpenCL and Cuda. Regarding the revamp you can follow the very detailed Picasso RFC at https://github.com/nim-lang/RFCs/issues/160 https://github.com/nim-lang/RFCs/issues/160 and the repo I'm currently building the runtime at https://github.com/mratsim/weave https://github.com/mratsim/weave. Obviously I am biaised as a Nim dev that uses Nim for both work and hobby so I'd rather have others that tried both comment on their experience.
- cdbattags 7y agoThis is massive and props to the team! I have a small prototype for interop between 0.1 and 0.3 futures which are also compatible with async/await first order. Excited for where this takes us! Can't wait for tokio 2.0 now. https://github.com/cdbattags/async-actix-web https://github.com/cdbattags/async-actix-web
- C14L 7y agoAn interesting presentation on the history of futures in Rust (from RustLatam 2019): https://www.youtube.com/watch?v=skos4B5x7qE https://www.youtube.com/watch?v=skos4B5x7qE
- pimeys 7y agoThe same day as async/await hits stable, the next Prisma alpha is released and is the first alpha that's based on Futures and async/await. https://github.com/prisma/prisma-engine/ https://github.com/prisma/prisma-engine/ Been working with the ecosystem since the first version of futures some years ago, and I must say how things are right now it's definitely much much easier. There are still optimizations to be made, but IO starts to be in a good shape!
- maccam912 7y agoWhat is this? The Github repo doesn't offer a description.
- pimeys 7y agoMaybe the website tells more? https://www.prisma.io/ https://www.prisma.io/ Basically we offer a code generator for typescript, migrations and a query engine to simplify data workflows. Go support is coming next.
- ClumsyPilot 7y agoMaybe, but you linked the repo and it don't even have link to the website, let alone a description. Looks like a great project, best of luck.
- pimeys 7y agoSorry, didn't mean this to be product advertisement, so I wanted to just link to the core code. The user-facing product is typescript and go and in different repositories. The backend is Rust and we jumped into the async/await train some months ago already. Wanted to share some experience and how quickly in the end we were able to get a working system out with the new apis.
- ClumsyPilot 7y agoI am perfectly happy for you to advertise , it's just that most people reading this probably are not rust developers, so it would be great to know what the project is about.
- jdance 7y agoI have never used async/await and cant really understand it. Is it like coroutines in lua? It seems very similar. But I guess its not limited to one thread like lua? Whats makes it better then threaded IO? Losing the overhead of threads? I like coroutines but thats mostly because they are not threads, they only switch execution on yield, and that makes them easy to reason about :)
- uryga 7y ago> Is it like coroutines in lua? idk about Lua, but afaik python's async is pretty much implemented on top of coroutines ("generators"). `await` is basically `yield` > I like coroutines but thats mostly because they are not threads, they only switch execution on yield, and that makes them easy to reason about :) pretty sure i've heard the same thing said about async io!
- jdance 7y agoI guess the thing that puzzles me is that if they are run threaded (concurrently) they seem just as hard to reason about as threaded IO to me. And that would leave the motivation to be performance gains by being able to reduce the amount of threads I guess (And that it is cool of course :)
- uryga 7y agothe coroutines are run sequentially by an "event loop"/"coroutine runner" that wakes them up and lets them run for a bit when appropriate, kind of like an OS's scheduler (on a single core machine). if the runner is the OS, `await foo(..)` is kind of like a syscall, where the coroutine is suspended and control is handed back to the runner to do whatever is requested. i guess the difference from normal threads (preemptive multitasking) is that you explicitly mark your "yield points" – places where your code gives control back to the runner – with `await` (cooperative multitasking). some believe that this makes async stuff easier to reason about, since in theory you can see the points where stuff might happen concurrently honestly i'm out of my depth re: async IO, haven't used it all that much :/ but if you're comfortable with python and want to dig into the mechanism of async/await, i really recommend this article: https://snarky.ca/how-the-heck-does-async-await-work-in-python-3-5/ https://snarky.ca/how-the-heck-does-async-await-work-in-pyth... it's long, but i found it very helpful – it actually explains how it all works without handwaviness. at the end the author implements a toy "event loop" that can run a few timers concurrently, which really made it click for me!
- MrBra 7y agoCan anybody share their thoughts on which key features / libs are still missing in Rust?
- fnord123 7y agoBinary crates. Sandboxed builds (I'll continue to use crates that have a build.rs which can do anything it wants, but I don't like it). Namespacing crates (a la Java) to deal with the name squatting issue.
- hechang1997 7y agoGenerics and compile time computation. I think Rust should achieve feature parity with c++ templates and constexpr.
- tracker1 7y agoThis is awesome... been waiting on this... looking at a lot at rocket and yew (really new with rust), and had been waiting to see the async stuff shake out before continuing (been holding for a few months now), may take a bit of time over the weekend to start up again.
- person_of_color 7y agoCan someone explain the benefit of this programming paradigm to other applications besides web servers/IO bound tasks?
- jdance 7y agoMy other question of similar nature also goes unanswered :( Maybe the primary benefit is that its new and sexy
- lenkite 7y agoDoes Rust offer composable futures ? Something like Javas CompletableFuture or Clojure's https://github.com/leonardoborges/imminent https://github.com/leonardoborges/imminent ?
- yazaddaruvala 7y agoYes you can use functions like CompletableFuture’s thenApply. However, Rust Futures have a very different implementation compared to CompletableFuture.
- stubish 7y agoThis seems very similar to Python's approach, which I've been finding poor to use. I was wondering if a more pleasant approach would be to add a 'defer' keyword to return a future from an async call, and have the default call be to await and return the result (setting up a default scheduler if necessary). Requiring the await keyword to be inserted in the majority of locations seems poor UX, as is requiring callsites to all be updated when you update your synchronous API to async.
- deleted 7y ago[deleted]
- sbmthakur 7y agoRust beginner here who writes a lot of async code in Node.js. If I am to start writing async code in Rust, should I directly pick up async-await? Or should I first understand how it is done in the current way?
- steveklabnik 7y agoYou should start with async-await, but know that the ecosystem is in the middle of catching up, and so you may run into packages that are more awkward to use at the moment.
- ekoutanov 7y agoExcellent work by the rust team. Must have taken significant changes to the scheduler.
- ldng 7y agoI would be interested to know if a comparison between async and sync API at level exists. I have this intuitive but probably wrong feeling that async often implies memory overhead.