> On Sep 11, 2017, at 1:15 PM, Kenny Leung via swift-evolution 
> <swift-evolution@swift.org> wrote:
> 
> I found a decent description about async/await here:
> 
> https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/
>  
> <https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/>
> 
> So it’s much more like runloop based callbacks in Foundation that 
> libdispatch. It’s complicated. Even the simplest example is super 
> complicated. 
> 
> It’s super implicit (like, “I’m going to package up every line of code from 
> await to the end of this function and turn it into a continuation”). That 
> seems to go against one of the primary principles of Swift, which is to make 
> things plain to the reader. I’d be interested to know what the call stack 
> looks like on the line after await.

This is pretty much how it would have to work for Swift as well. The call stack 
after the await (in C#) would either start at the runloop and go through the 
futures API (usually Task) or it would start at whatever code satisfied the 
async request.

It’s true that this can make it more difficult to understand stack traces. In 
most cases the original call stack is lost. Microsoft has made changes to 
Visual Studio in order to show kind of an alternative stack trace for tasks to 
try to make this better. I think they also made things like F10 (step over) and 
F11 (step out) do the natural thing (i.e., wait for the continuation).

> 
> The doc takes away some of the mystery, but leaves major questions, like: 
> await is used to yield control to the parent, but at the bottom of the call 
> stack, presumably you’re going to do something blocking, so how do you call 
> await?

One of the common misconceptions about async/await (which I also had when I 
first encountered it) is that there must be a blocking thread somewhere. It 
doesn’t work that way. The “bottom of the call stack” is typically either a run 
loop or a thread pool with a work queue (really just another kind of run loop). 
I guess you’re right in the sense that those kinds of run loops do block, but 
they’re not blocking on any particular piece of work to be done. They’re 
blocking waiting for ANY more work to be done (either events or items placed in 
the work queue).

The way that the continuation works is that it is placed onto one of those 
queues. For the UI thread it’s kind of like doing performSelectorOnMainThread: 
(the .Net equivalent is usually called BeginInvokeOnMainThread). For a thread 
pool there’s another API. For GCD this would be like doing a dispatch_async. 
It’s putting the continuation callback block onto a queue, and that callback 
will be called when the run loop or the thread pool is able to do so.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to