不仅仅是控制台应用程序,实际上:异步方法在GUI程序中尤为有用。
原因:GUI程序在设计上就要求,所有的显示变化都必须在主GUI线程中完成,如 点击按钮、展示标签、移动窗体等。Windows程序是通过消息来实现这些动作的,消息被放入由消息泵管理的消息队列中,消息泵从队列中取出一条消息,并调用它的处理程序代码。当 处理程序代码 完成时,消息泵获取下一条消息并循环这个过程。
下面展示同步/异步的区别:
1、同步
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
namespace MessagePump
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
//点击按钮后,按钮的处理程序
private void btnDoStuff_Click(object sender, RoutedEventArgs e)
{
//1.禁用按钮:这样在处理程序执行期间,用户就不能再次点击了
btnDoStuff.IsEnabled = false;
//2.将标签文本改为Doing Stuff
lblStatus.Content = "Doing Stuff";
//3.将程序休眠4s:模拟某个工作
Thread.Sleep(4000);
//4.将标签文本改为原始文本
lblStatus.Content = "Not Doing Anything";
//5.启用按钮
btnDoStuff.IsEnabled = true;
}
}
}
当点击按钮后,什么都没有发生。而且如果在点击按钮后移动窗体,会发现它已经冻结,不会移动---直到4s之后,窗体才突然出现在新位置。
2、异步方法---使用async/await特性
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
namespace MessagePump
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private async void btnDoStuff_Click(object sender, RoutedEventArgs e)
{
btnDoStuff.IsEnabled = false;
lblStatus.Content = "Doing Stuff";
//处理程序的消息队列中:先将上面2行代码压入消息队列,将下面的delay消息先从处理器上摘下来,等4s之后,再将自己压入队列。那么:所有的消息就不用等待了,这就可以保持GUI的实时响应了。
//当到达await 语句时,处理程序返回到调用方法,这时处理器已经压入队列中的上面2条语句得以处理。
//等完成这里的空闲任务(等待4s之后)后,接着继续执行处理程序中的最后2条消息。
await Task.Delay(4000);
//4s之后,文字又变为"Not Doing Anything"
lblStatus.Content = "Not Doing Anything";
btnDoStuff.IsEnabled = true;
}
}
}