Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a `Task` context switch before its first `await`?

Tags:

c#

async-await

Is the creation of a Task a context switching point, or only when it starts to await or do other asynchronous things?

For example if I have these functions:

async Task Foo()
{
  Console.WriteLine("In Foo");
  await bar();
}

void CallFoo()
{
  var task = Foo();
  Console.WriteLine("Returned from Foo");
  task.Wait();
}

Is it possible for "Returned from Foo" to print before "In Foo"?

like image 504
bfops Avatar asked Oct 05 '18 18:10

bfops


People also ask

Does await cause context switch?

No. It schedules the remaining code to run on the correct context. That context might be a threadpool thread. It might be the UI thread.

Which is the situation under which context switching will not be done?

You can't directly switch a process from the running state to the ready state. You have to save the context of that process. If you are not saving the context of any process P then after some time, when the process P comes in the CPU for execution again, then the process will start executing from starting.

How often does context switch happen?

A context-switch must occur when one thread is a candidate for CPU time and no CPUs are currently available (in use by another thread). A context switch also occurs when you call Thread.

How long does it take to context switch?

Each context switch takes the kernel about 5 μs (on average) to process. However, the resulting Cache misses add additional execution time that is difficult to quantify. The more frequent the context switches, the more your CPU utilization degrades.


1 Answers

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.

like image 109
Eric Lippert Avatar answered Oct 11 '22 20:10

Eric Lippert