S Itzik
S Itzik

Reputation: 564

ConfigureAwait(false) doesn't make the continuation code run in another thread

I have a code which runs on thread1. I call a function in a synchronic way (using async method but it shouldn't disturb me - async method doesn't turn code to be asynchronic).

I have an await with ConfigureAwait set to false, so I understood the code after it is a task continuation which suppose to run in a different thread than the code before the await (because ConfigureAwait was set to false).

By my test - All code run in the same thread. How is it? Why doesn't the code, below the await, run on a different thread? This is the code:

public async void F1()
{
    Console.WriteLine($"Thread.CurrentThread.ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
    int x = await F2().ConfigureAwait(false);
    Console.WriteLine($"Thread.CurrentThread.ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
}

private async Task<int> F2()
{
    Console.WriteLine("Begins F2");
    Console.WriteLine($"Thread.CurrentThread.ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
    Console.WriteLine("Finishes F2");
    return 7;
}

This is the output:

Thread.CurrentThread.ManagedThreadId=1
Begins F2
Thread.CurrentThread.ManagedThreadId=1
Finishes F2
Thread.CurrentThread.ManagedThreadId=1

Upvotes: 4

Views: 1185

Answers (3)

Waescher
Waescher

Reputation: 5737

The naming is very unfortunate but it's actually easy to explain.

  • If you don't use ConfigureAwait(false) you basically say the opposite ConfigureAwait(true) which tells the runtime that you want to proceed on the same context as you were called from.
  • By using ConfigureAwait(false) to tell the runtime that you don't need to proceed on the same context as you were called from - but it's up to the runtime to decide which context makes sense then, so it's likely to be another but it does not have to be this way.

Microsoft could have made this easier by using different methods like these for example:

// context is 'A'
await Do().KeepContext();
// context is 'A'

// context is 'A'
await Do().FreeContext();
// context is 'A' but could also be 'B' or 'C'

Taken from my article https://github.com/awaescher/ObviousAwait

Upvotes: 0

Hans Kesting
Hans Kesting

Reputation: 39329

It is not "supposed to run in a different thread context", it is allowed to. In the opposite case (ConfigureAwait(true)) it must continue on the same thread context.

Furthermore when there is nothing to await (inside the method), the "async" method runs synchronously so doesn't need to return to some thread context, it is still on it.

Upvotes: 9

Stephen Cleary
Stephen Cleary

Reputation: 456757

I have an await with ConfigureAwait set to false, so I understood the code after it is a task continuation which suppose to run in a different thread than the code before the await (because ConfigureAwait was set to false).

No. There are a couple of misunderstandings here.

The first misunderstanding is regarding what ConfigureAwait(false) does.

ConfigureAwait (and await) have nothing to do with threading directly. By default, await captures a context - the current SynchronizationContext or TaskScheduler. This context could resume on the same thread (e.g., UI SynchronizationContexts commonly do this), but "context" does not necessarily mean "thread" (e.g., the ASP.NET pre-Core SynchronizationContext can resume on any thread pool thread).

What ConfigureAwait(false) actually does is skip capturing that context. So the thread pool context is used, which may run on any thread pool thread. Note that if the code before await was running on a thread pool thread, it may resume on any thread pool thread, including the thread that it was running on before.

The second misunderstanding is regarding when ConfigureAwait(false) is applied.

await will first check to see if its awaitable is complete, and only then will it actually behave asynchronously. So if you await an already-completed task, the ConfigureAwait(false) is never even considered - the code just continues running synchronously.

How can I enforce it to run on a different thread then?

Use Task.Run. Task.Run is the proper tool to use when you need to run code on a thread pool thread.

Upvotes: 9

Related Questions