目录
- 原因分析
- 解决方式
- 一 添加 async await
- 二 添加同步方法去调用异步方法
原因分析
我们在执行一下代码的时候会发现程序卡死了,首先winform项目中能够修改控件的必须是UI线程,主线程遇到await返回后会将下面未执行的代码打包交给线程池,由线程池分配线程再处理,而因为winformUI线程的特殊性,丢给线程池后会有上下文环境的问题,而这个上下文环境的问题只有主线程会涉及到,所以打包后的内容优先由主线程来执行。而这个特殊性导致winform在await之后运行的线程一定是UI线程。
private void btnSync_Click(object sender, EventArgs e)
{
Console.WriteLine($"This is btnSync_Click Start,ThreadId={ Thread.CurrentThread.ManagedThreadId}");
var task = this.CalculationAsync(1_000_000);
task.Wait();
long lResult = task.Result;//同步阻塞,主线程在等结果
//long lResult = this.GetCalculationAsync(1_000_000);//换个线程去调用async方法,有点恶心
Console.WriteLine($"This is btnSync_Click End,ThreadId={ Thread.CurrentThread.ManagedThreadId}");
this.lblSync.Text = lResult.ToString();
}
private async Task<long> CalculationAsync(long total)
{
var result = await Task.Run(() =>
{
Console.WriteLine($"This is CalculationAsync Start,ThreadId={ Thread.CurrentThread.ManagedThreadId}");
long lResult = 0;
for (int i = 0; i < total; i++)
{
lResult += i;
}
Console.WriteLine($"This is CalculationAsync End,ThreadId={ Thread.CurrentThread.ManagedThreadId}");
return lResult;
});
return result;//await后面的代码,会要求主线程来执行
}
解决方式
一 添加 async await
private async void btnAsync_Click(object sender, EventArgs e)
{
Console.WriteLine($"This is btnAsync_Click Start,ThreadId={ Thread.CurrentThread.ManagedThreadId}");
long lResult = await this.CalculationAsync(1_000_000);
Console.WriteLine($"This is btnAsync_Click End,ThreadId={ Thread.CurrentThread.ManagedThreadId}");
this.lblAsyncResult.Text = lResult.ToString();//必须是UI线程,更新能成功是因为winform的UI线程特殊性,await之后的线程一定是UI线程
}
二 添加同步方法去调用异步方法
private long GetCalculationAsync(long total)
{
var taskLong = Task.Run(() =>
{
var task = this.CalculationAsync(total);
long lResult = task.Result;//子线程
return lResult;
});
return taskLong.Result;//主线程在等Result
}
还没有评论,来说两句吧...