Python Coroutines with Async and Await
lwn.net
lwn.net
First issue - the necessity for at least two of each method: "DoSomething" and "DoSomethingAsync". Weak. Now as a library developer, you just doubled your work. Sure, sometimes one method could wrap the other. But it's still weak sauce.
I much prefer the Go model - you only code "sync" API's, and let the consumer of your API wrap it in a go-routine and make it "async" if they wish. Much simpler, better, composable.
Async/await is also gaining traction in Javascript. Really, really sad we still try to avoid concurrent programming and how to do it right vs easy.
public Task<ReturnType> DoSomethingAsync(args) {
return await Task.Run(() => DoSomething(args));
}
In fact, it's so easy that I can think of at least two ways to automatically add async methods, either at compile time or at runtime. I would have to look into it a little more, but I think you could even write an extension method on object that would add the async version via reflection.The upside of async/await is that you avoid callback hell. The code stays cleaner and is easier to read, both of which seem like wins to me.
Look at Go's CSP implementation, or Erlang's. No callback hell anywhere.
Ultimately, it's possible to be semi-successful in designing scalable, concurrency-aware software with just after-thought libraries and language support, but is that really the way forward, long-term?
The underlying idea behind async/await is that synchronous methods shouldn't exist in the first place--you'd only have the asynchronous API. Async/await enhances that model by turning the promises' functional interface (which requires interesting binding to handle loops/recursion) back into an imperative control interface.
Furthermore, "asynchronous" code doesn't need separate threads. A scheduler and green threads is more than enough.
Have you seen Go? You should take a look at it. It makes writing concurrent code basically trivial, using "green" threads and channels and a neat little "select" statement.
If they were to support only .NET 4.5 or higher, then you can just call any async method in a sync manner simply by doing httpClient.GetAsync(...).Result
async/await in C# is a beautiful thing.
However, in javascript the idea works because javascript is single threaded so you can be sure that the await-"callback" is always run when nothing else is. Explicitly defining some kind of message-pump that you can control the await-continuation yourself would be way around this in multi threaded languages but i haven't found a way to do so in c#.
I'm wondering how this will be handled in async. Will everything need to be reimplemented as separate async implementations, or is there a way to have a common implementation that supports both sync and async? Will e.g. async HTTP be added to the standard library?
I think this was a topic of discussion when they first added asyncio, but I never saw an official decision.
What was the last truly-new language feature that became popular across other languages like this?
What C# (actually it was F#) introduced was the specific 'await' and 'async' syntax keywords. Those are being copied in other languages, and they're just sugar over coroutines.
[1] http://www.cambridge.org/gb/academic/subjects/computer-scien...
[2] http://blog.mekk.waw.pl/archives/14-Twisted-inlineCallbacks-...
We're basically just getting the up to speed with ML from the 80's.
For example: if I'm calling an IO method that returns a value it should be able to figure that out and orchestrate the code to run asynchronously and await for the value when it's referenced. If I have several asynchronous calls methods in a method it should be able to optimize it so they all run in parallel as optimized as possible.
It might need some added declarative syntax on methods but I'd rather prefer that and make the compiler smarter, instead of offloading that complexity on the programmer per default. Sure you should be able to explicitly control asynchronicity if needed but in most cases that doesn't seem optimal nor necessary
Adding async/await all over your code adds to the "crud" that makes code more verbose and harder to read and understand
It's kinda the same thing except telling the compiler what to do you instruct it what's safe to do, and it can make smart decisions from that. If the compiler/environment detects any ambiguity or risk it might even query the programmer to declare his intent
Yes, basically, they are explicitly declaring dataflow dependencies. There are languages that handle this automatically, e.g., Oz [0].
OTOH, async/await is a solution that can be retrofitted onto an existing language that isn't fundamentally designed around dataflow dependencies without changing the semantics of existing code.
[0] as implemented in the Mozart Programming System, https://mozart.github.io/mozart-v1/doc-1.4.0/
Having calls be implicitly parallel makes it difficult for the programmer to predict what could be happening elsewhere in the program. E.g., this passage from the Oz documentation[1]:
"Oz 1, supports a fine-grained notion of concurrency where each statement can potentially be executed concurrently. This results in a fine-grained model similar to the actor model. A good exposition of the Oz 1 programming model is given in [Smo95]. Our experience using Oz 1 showed that this kind of model, while theoretically appealing, makes it very hard for the programmer to control the resources of his/her application. It is also very hard to debug programs and the object model becomes unnecessarily awkward."
For I/O in particular it is also difficult for the machine to know what is safe to do in parallel. For instance, two writes to the same file probably has to happen in order. What about writes to different files? What about HTTP requests? Most I/O has the potential to produce wrong results if rearranged in arbitrary order, and requiring the programmer to mark them sequential becomes a potential source of error and a cognitive burden.
In most cases it's better to be slow and correct by default, and allow the programmer to explicitly run things in parallel in the cases it matters.
[1] http://mozart.github.io/mozart-v1/doc-1.4.0/tutorial/node1.h...
The benefit of this approach is that the compiler should be able to see more opportunities for optimization and also result in fewer bugs.
It's not an efficient implementation - it was really meant as a proof of concept that you can use async/await in your own code without any reference to asyncio.
[1] https://gist.github.com/vrajivk/c505310fb79d412afcd5#file-si... https://gist.github.com/vrajivk/c505310fb79d412afcd5#file-ch...
In the simplest case in Go, it's easy for me to toss off some concurrent processing and not wait or care about what happens in those functions. For all intents and purposes, it feels like parallel execution (I know, I know).
I can't quite wrap my head around how generators or async/await gives me the same functionality. What am I missing?
Async/await doesn't feel like lightweight threads because you need to explicitly await tasks. You could invert the keyword usage to match Go (implicit await, explicit go) and end up with something like goroutines.
EDIT: await asyncio.gather(fut1, fut2)
await asyncio.wait([fut1, fut2])