Is ConfigureAwait(false) required on all levels of the async chain when no real I/O call is involved?

前端 未结 2 1783
既然无缘
既然无缘 2021-01-20 03:10

Implementing a reusable adaptor type of library on top of Azure Document Db Client SDK.

The library can run anywhere, not only in an ASP.NET Core web service, but i

2条回答
  •  隐瞒了意图╮
    2021-01-20 03:45

    ConfigureAwait(false) is used to prevent execution on initial SynchronizationContext. If you're working on library which doesn't need access to UI thread for instance (in case of WPF or WinForms) you should use ConfigureAwait(false) on all levels. Otherwise SynchronizationContext will be restored. Here is an example of simple WinForms application:

    public partial class Form1 : Form
    {
        static readonly HttpClient _hcli = new HttpClient();
    
        public Form1()
        {
            InitializeComponent();
        }
    
        private static string log;
        private async void button1_Click(object sender, EventArgs e)
        {
            log = "";
            await M3();
            MessageBox.Show(log);
        }
    
        static async Task M3()
        {
            LogBefore(nameof(M3));
            var str = await M2();
            LogAfter(nameof(M3));
            return str;
        }
    
        static async Task M2()
        {
            LogBefore(nameof(M2));
            var str = await M1();
            LogAfter(nameof(M2));
            return str;
        }
    
        static async Task M1()
        {
            LogBefore(nameof(M1));
            var str = await _hcli.GetStringAsync("http://mtkachenko.me").ConfigureAwait(false);
            LogAfter(nameof(M1));
            return str;
        }
    
        static void LogBefore(string method)
        {
            log += $"before {method} {Thread.CurrentThread.ManagedThreadId} {SynchronizationContext.Current == null}, ";
        }
    
        static void LogAfter(string method)
        {
            log += $"after {method} {Thread.CurrentThread.ManagedThreadId} {SynchronizationContext.Current == null}, ";
        }
    }
    

    Output:

    before M3 1 False
    before M2 1 False
    before M1 1 False
    after M1 12 True //sync.context skipped because of .ConfigureAwait(false)
    after M2 1 False //sync.context restored
    after M3 1 False //sync.context restored
    

提交回复
热议问题