简体   繁体   中英

Await and different thread id for the same code

I have a problem understanding why the rest of the function after using async is done in different threads for the same code. Take an example - in CODE 1 the rest of the function is executed in thread 3, which is logical, because the DoAsyncWork function was executed in it.函数的其余部分在线程 3 中执行,这是合乎逻辑的,因为 DoAsyncWork 函数是在其中执行的。

In the case of CODE 2, the rest of the function is still executed in thread 1., although the function DoWorkAsync was done in thread 3.函数的其余部分仍然在线程 1 中执行,尽管函数 DoWorkAsync 在线程 3 中完成。

The only difference is that btnCallMethod_Click is called from Windows Forms - it handles Click event for a standard button.

What does it depend on ? Does Windows Forms trigger events in any special way that the thread does not change?

//CODE 1:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp61
{

    class Test
    {
        public event EventHandler Click;
        public string TestString { get; set; }
        internal void DoClick()
        {
            Click?.Invoke(this, new EventArgs());
        }

        public async void RunClick(object sender, EventArgs e)
        {
            Console.WriteLine("Before async call " + Thread.CurrentThread.ManagedThreadId); // Thread id=1
            (sender as Test).TestString = await DoAsyncWork(1);
            Console.WriteLine("After async call " + Thread.CurrentThread.ManagedThreadId); //Thread id=3 OK
        }

        private Task<string> DoAsyncWork(int step)
        {
            return Task.Run(() => {
                Thread.Sleep(10000);
                Console.WriteLine($"DoAsyncWork() " + Thread.CurrentThread.ManagedThreadId); //Thread id=3
                return "555";
            });
        }
    }

    class Program
    {     
        static async Task Main(string[] args)
        {
            Test x = new Test();
            x.Click += x.RunClick;
            x.DoClick();
            Console.ReadKey();
        }
    }
}

/////////////////////////////////////////////////////////////////////
// CODE 2:
private async void btnCallMethod_Click(object sender, EventArgs e)
        {
            Console.WriteLine("step 1-" + Thread.CurrentThread.ManagedThreadId); //Thread id=1
            this.Text = await DoWorkAsync();
            Console.WriteLine("step 2-" + Thread.CurrentThread.ManagedThreadId); //Thread id=1 Still 1 !!! Why ? Should  be 3
        }

        private async Task<string> DoWorkAsync()
        {
            return await Task.Run(() =>
            {
                Thread.Sleep(10000);
                Console.WriteLine("step 99-" + Thread.CurrentThread.ManagedThreadId); // Thread id =3
                return "Done with work!";
            });
        }

No, it shouldn't be 3 in the code 2 . It's all about synchronization context .

There is no synchronization context in console application, so task continuations are executed on thread pool in code 1 .

WPF and WinForms applications have synchronization context to route execution back to UI thread to modify controls for instance.

Try this this.Text = await DoWorkAsync().ConfigureAwait(false); in the 2nd example and your code won't be returned to thread 1 .

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

What Is SynchronizationContext

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM