C# 相同代码的等待和不同线程id

C# 相同代码的等待和不同线程id,c#,async-await,C#,Async Await,我很难理解为什么在使用async之后,函数的其余部分在同一代码的不同线程中完成。例如,在代码1中,RunClick函数的其余部分在线程3中执行,这是合乎逻辑的,因为DoAsyncWork函数是在线程3中执行的 在代码2的情况下,btnCallMethod_Click函数的其余部分仍然在线程1中执行,尽管函数DoWorkAsync是在线程3中执行的 唯一的区别是,btnCallMethod\u单击 从Windows窗体调用-它处理标准按钮的单击事件 这取决于什么?Windows窗体是否以线程不更改

我很难理解为什么在使用async之后,函数的其余部分在同一代码的不同线程中完成。例如,在代码1中,RunClick函数的其余部分在线程3中执行,这是合乎逻辑的,因为DoAsyncWork函数是在线程3中执行的

在代码2的情况下,btnCallMethod_Click函数的其余部分仍然在线程1中执行,尽管函数DoWorkAsync是在线程3中执行的

唯一的区别是,
btnCallMethod\u单击
从Windows窗体调用-它处理标准按钮的单击事件

这取决于什么?Windows窗体是否以线程不更改的任何特殊方式触发事件

//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!";
            });
        }
//代码1:
使用制度;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用系统线程;
使用System.Threading.Tasks;
名称空间控制台EAPP61
{
课堂测试
{
公共事件事件处理程序单击;
公共字符串TestString{get;set;}
内部void DoClick()
{
单击?.Invoke(这是新的EventArgs());
}
公共异步void RunClick(对象发送方,事件参数e)
{
Console.WriteLine(“异步调用之前”+Thread.CurrentThread.ManagedThreadId);//线程id=1
(发送方作为测试)。TestString=Wait-DoAsyncWork(1);
Console.WriteLine(“异步调用后”+Thread.CurrentThread.ManagedThreadId);//线程id=3 OK
}
私有任务DoAsyncWork(int步骤)
{
返回任务。运行(()=>{
睡眠(10000);
Console.WriteLine($“DoAsyncWork()”+Thread.CurrentThread.ManagedThreadId);//线程id=3
返回“555”;
});
}
}
班级计划
{     
静态异步任务主(字符串[]args)
{
测试x=新测试();
x、 Click+=x.RunClick;
x、 DoClick();
Console.ReadKey();
}
}
}
/////////////////////////////////////////////////////////////////////
//代码2:
私有异步void btnCallMethod_单击(对象发送方,事件参数e)
{
Console.WriteLine(“步骤1-”+Thread.CurrentThread.ManagedThreadId);//线程id=1
this.Text=await-doworksync();
Console.WriteLine(“步骤2-”+Thread.CurrentThread.ManagedThreadId);//线程id=1还是1!!!为什么?应该是3
}
专用异步任务DoWorkAsync()
{
返回等待任务。运行(()=>
{
睡眠(10000);
Console.WriteLine(“步骤99-”+Thread.CurrentThread.ManagedThreadId);//线程id=3
返回“完成工作!”;
});
}

不,在
代码2中不应该是3。这一切都是关于
同步上下文的

控制台应用程序中没有
同步上下文
,因此任务继续在
code 1
中的线程池上执行

WPF
WinForms
应用程序具有
同步上下文
将执行路由回
UI
线程以修改控件

试试这个
this.Text=await-doworksync().ConfigureAwait(false)在第二个示例中,您的代码将不会返回到线程
1

请在这里检查我的答案


您是否在问为什么
await
在UI中的同一个线程中继续,但如果不是UI,则在不同的线程中继续?您可以在中找到一些见解。在异步代码中使用Thread.Sleep()从来都不好-尝试将其替换为await Task.Delay(),并从DoWorkAsync()中删除不必要的Task.Run(),然后查看是否仍然得到相同的结果。是的,问题是:如果从UI调用方法,为什么await会在同一线程中继续,如果它是从我的私人课(活动)中调用的,为什么不呢。