Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is ConfigureAwait(true) always get back to the orignial thread, even when the callee method does ConfigureAwait(false) internally? [duplicate]

I was expecting to get back to Thread#1 at location 1.2, but I did not. Is there a way to get back to UI thread after making the async call? Thanks

Also I cannot make the top level method async. Not sure if async all the way will solve this issue but I don't have that choice right now.

class Program
{
    static void Main(string[] args)
    {
        ComputeThenUpdateUI().Wait();
    } 
    static async Task ComputeThenUpdateUI()
    {
        Console.WriteLine($"1.1 {Thread.CurrentThread.ManagedThreadId}");
        await ExpensiveComputingNonUI().ConfigureAwait(true);
        Console.WriteLine($"1.2 {Thread.CurrentThread.ManagedThreadId}");
    } 
    static async Task ExpensiveComputingNonUI()
    {
        Console.WriteLine($"2.1 {Thread.CurrentThread.ManagedThreadId}");
        await Task.Delay(3000).ConfigureAwait(false);
        Console.WriteLine($"2.2 {Thread.CurrentThread.ManagedThreadId}");
        await Task.Delay(3000).ConfigureAwait(false);
        Console.WriteLine($"2.3 {Thread.CurrentThread.ManagedThreadId}");
    }
}
 
 
Output:
1.1 1
2.1 1
2.2 4
2.3 4
1.2 4

like image 816
Carol Avatar asked May 31 '18 03:05

Carol


1 Answers

Re : Doesn't .ConfigureAwait(true) mean that flow will return to the same thread once the await completes?

No, in most cases, there is no guarantee. Stephen Cleary has a definitive answer:

This "context" is SynchronizationContext.Current unless it is null, in which case it is TaskScheduler.Current. (If there is no currently-running task, then TaskScheduler.Current is the same as TaskScheduler.Default, the thread pool task scheduler).

It's important to note that a SynchronizationContext or TaskScheduler does not necessarily imply a particular thread. A UI SynchronizationContext will schedule work to the UI thread; but the ASP.NET SynchronizationContext will not schedule work to a particular thread.

i.e. only calls made from the UI thread of e.g. WPF or Windows Forms are guaranteed to return to the same thread. If you really need to return to the same thread, then you'd need to do customization to ensure the continuation is scheduled on the original thread.

Unless this is essential (such as for UI threads), returning to the same thread is generally undesirable as this can reduce performance (if there is contention for the thread) and lead to deadlocks

Re: Cannot make the top level main method async

This is now possible in C#7.1:

public static async Task Main(string[] args)
{
    // Can await asynchronous tasks here.
}
like image 69
StuartLC Avatar answered Nov 14 '22 21:11

StuartLC