我想我在这里遗漏了一些东西.. 我期望对CountCharsAsync()的调用是非阻塞的。但它似乎并非如此。当我点击我的按钮时,前五秒没有任何事情发生..并且UI被卡住......
但第二个版本没问题。
有人可以解释这两种方式之间的区别......
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AsyncAwaitExample
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private async void button1_Click(object sender, EventArgs e)
{
textBox1.Text += "Count is : ";
int count = await CountCharsAsync();
textBox1.Text += count;
textBox1.Text += "\r\n-----------\r\n";
textBox1.Text += "Count is : ";
Task<int> tsk = new Task<int>(CountChars);
tsk.Start();
int count2 = await tsk;
textBox1.Text += count2;
}
private int CountChars()
{
int count = 50;
Thread.Sleep(5000);
return count;
}
private async Task<int> CountCharsAsync()
{
int count = 50;
Thread.Sleep(5000);
return count;
}
}
}
答案 0 :(得分:1)
您正在异步方法中调用Thread.Sleep
。这将阻止它正在运行的任何线程......这仍然是UI线程。调用异步方法本身不会启动新线程。可能涉及其他线程,具体取决于方法中发生的具体情况,但在第一个await
表达式之前,该方法将在与调用代码相同的线程上同步执行...并且您的异步方法没有任何线程等待表达式(应该已经给你一个警告)。
您应该使用:
await Task.Delay(5000);
代替。这是一种“异步等待”。这样,UI线程将不会被阻止。 CountCharsAsync
返回的任务将在约5秒后完成,此时button1_Click
的下一部分将会执行。
将此与此代码进行比较:
Task<int> tsk = new Task<int>(CountChars);
tsk.Start();
这将在线程池上的默认任务调度程序中执行CountChars
。阻止 线程根本不会影响UI。 (正如评论中所指出的那样,现在这不是启动任务的好方法。要么调用异步方法,要么使用Task.Run
。)
答案 1 :(得分:0)
虽然Daisy的回答使它不能阻止UI,但你的CountCharsAsync方法是“假的”异步。如果您有Resharper(不确定这是VS或R#的功能),您将收到警告:
异步方法缺少'await'运算符并将同步运行
这是因为异步任务没有完成所有的魔法 - 在你的情况下,它绝对没有任何意义。无处使你在另一个线程上运行。
正确实施将是:
private int CountChars()
{
int count = 50;
Thread.Sleep(5000);
return count;
}
private Task<int> CountCharsAsync() // notice no async!
{
return Task.Run(CountChars);
}
如果你用一个for循环替换Thread.Sleep到最大整数,Daisy的实现仍会阻塞。
我的版本实际上将执行转移到新线程。