![]() ![]() That's generally fine, with some notable exceptions.) The continuation generally isn't guaranteed to run on the same thread as where we started. (We needn't think about the particulars of threads too much here, but some thread clearly eventually marks that Task object as completed, so clearly some thread will be in a good position to 'notice' that it's time to act on that `ContinueWith` now. Things can compose nicely in this way `Task#ContinueWith` returns another Task. Internal to your function, the network activity itself will also have taken the form of a standard-library Task, and our function will have made use of its `ContinueWith` method. The caller of your function can use the `Task#ContinueWith` method, which enqueues work to occur if/when the Task completes, using the result value from the Task. Your function will quickly return a non-completed Task object, which will enter a completed state only once the network activity has concluded and processing has occurred to give the final `int` value. Your function will have a return-type of `Task`. Net, your function might do slow IO (network activity, say) then process the result to produce an int. I realise we're not talking C#/.Net, but that's what I know: in. It's best to treat 'await' as syntactic sugar, and to dig in to the underlying concepts. await != join_thread(), but doesn't execution of the current scope of code halt while it waits for the future we are `.await`-ing to complete? ![]() Code remains linearly readable despite being highly asynchronous. Less boilerplate code for asynchronous calls.Ģ. To me those are the 2 biggest gains from async.ġ. This makes the code much easier to reason about. Rather than chasing down async callbacks and other boilerplate concepts to manually handle asynchronous requests, the code reads like its synchronous twin. Second, await is MUCH EASIER for future developers to process because it looks exactly like any other method call and makes it easy to reason about the logic flow of the code. Go do something useful with this thread and get back to me." This was possible before using various asynchronous design patterns, but all of them were clunky, in that they required boilerplate code to do what the compiler should be able to figure out on its own: Rather than consume the current thread while waiting, you're telling the run-time, go ahead and resume another task that has reached the end of its await. In edge cases where there is only 1 await in the queue for 1 process with 1 thread you gain nothing.īut you're accurately describing an edge case where await has limited value.Īwait's true power shows up when you anticipate having multiple in-flight operations that all will, at overlapping points, be waiting on something. So, the power of async await is no greater than the thread pool manager sitting under it. Remember again, that it is basically transformed by the compiler into the second form. Second = await server.getMoreStuff(result+1) Synchronous code that tries to be asynchronous:Ī lot of JS code used to look like this hideous monstrosity. Internally, the compiler rewrites it to (roughly) the second form. Once server.getStuff returns, the callback passed to it is called with the result. Server.getStuff(lambda result: print(result)) Here is synchronous code, that tries to be asynchronous: I can't wait until the async book is done, it's really hard remembering which bits worked which way at which time, to be honest.Īsync/await are coroutines and continuations (bear with me). And executors don't need to know these details, they just need to call poll at the right time, and in accordance with their wakers. Tokio started before this style of API existed, and so bundles a few concepts in the current stack (though honestly, an integrated solution is nicer in some ways, so I don't think it's a bad thing, just that it makes it slightly easier to conflate the pieces since they're all provided by the same package.)Īsync/await, strictly speaking, is 100% agnostic of all of this, because it just produces stuff with the Futures interface these bits are inside the implementation of leaf futures. It would construct the waker to do the right thing with epoll. So it's not so much that the executor needs to know details about how to do the polling but the person implementing socket.read() needs to implement the future correctly. ![]() The second is that they need to register a "waker" with the executor before they return pending. So, futures have basically two bits of their API: the first is that they're inert until the poll is called. This stuff has changed a bunch over the last few years :) ![]()
0 Comments
Leave a Reply. |
AuthorWrite something about yourself. No need to be fancy, just an overview. ArchivesCategories |