Is it possible for "Returned from Foo" to print before "In Foo"?
In the program as you've written it, no, that is not possible.
If you have a different program that runs a worker thread, then you have all the usual issues of ordering side effects between threads. There is nothing special about "async/await" that makes those issues go away.
Is the creation of a Task a context switching point, or only when it starts to await or do other asynchronous things?
Let's be precise by what we mean by a "context switching point".
A method in C# can do one of four things:
- Run forever
- Return normally
- Throw
- Suspend -- which is what I think you mean by "context switch".
A method marked async
can suspend, but they only suspend when they await
a non-completed awaitable. Awaiting a completed awaitable does not suspend, but it can throw.
Tasks returned by async
methods are hot. That is, the asynchronous workflow begins and it runs until it returns, throws or suspends. It is possible to create a "cold" task with the Task
constructor, and that doesn't start until you call Start
on it. Normally you would not do that unless you were writing your own task scheduler.
Note that this is different than iterator blocks. A common mistake is:
IEnumerable<int> GetMeSomeInts(int x)
{
if (x < 0)
throw new SomeException();
for (int i = 0; i < x; i += i)
yield return i;
}
If you say
var nums = GetMeSomeInts(-1); // 1
foreach(int num in nums) // 2
...
Then the throw does not happen on line 1, it happens on line 2! Iterator blocks do not run up to the first yield
when you call them. They suspend immediately and do not execute until iterated in the foreach
. Be careful, particularly if you are working with both async and iterator coroutines in the same program.