C# 使用async Wait时语句执行的随机序列
我有一个非常简单的程序,如下所示C# 使用async Wait时语句执行的随机序列,c#,asynchronous,async-await,C#,Asynchronous,Async Await,我有一个非常简单的程序,如下所示 public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); Task task = DemoCompletedAsync(); MessageBox.Show("Method returned");
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Task task = DemoCompletedAsync();
MessageBox.Show("Method returned");
MessageBox.Show("Exiting .....");
}
static async Task<string> DemoCompletedAsync()
{
MessageBox.Show("Before first await");
await Task.Run(() => GetID());
MessageBox.Show("After first await");
return "Demo";
}
public static int GetID()
{
Thread.Sleep(2000);
return 1;
}
}
公共部分类主窗口:窗口
{
公共主窗口()
{
初始化组件();
任务任务=DemoCompletedAsync();
Show(“返回的方法”);
MessageBox.Show(“正在退出…”);
}
静态异步任务DemoCompletedAsync()
{
MessageBox.Show(“在第一次等待之前”);
等待任务。运行(()=>GetID());
MessageBox.Show(“首次等待后”);
返回“演示”;
}
公共静态int GetID()
{
《睡眠》(2000年);
返回1;
}
}
在没有调试模式的情况下运行程序时,消息框以正确的顺序显示。
i、 e.“在第一次等待之前”
“返回的方法”
“正在退出…”
“第一次等待之后” 但在调试时,语句会以随机方式执行,在
MainWindow()
和DemoCompletedAsync
框中的消息以以下方式显示:
“在第一次等待之前”--来自
DemoCompletedAsync
“返回的方法”--来自
mainwWindows
“首次等待后”--来自
DemoCompletedAsync
“正在退出…”——从
main窗口
根据理论,在方法名称中使用async
关键字告诉编译器,此方法将使用wait关键字等待异步操作,一旦遇到wait关键字,控件将传递给调用代码。但是,由await关键字表示的异步操作将继续执行。异步操作完成后,将执行方法的其余部分。所以为什么我会出现这种奇怪的行为,比如一些语句从main窗口执行,而另一些语句则从DemoCompletedAsync
相互切换。我还发现了另一个与消息框相关的问题。显示是模态对话框。第二个窗口在第一个窗口关闭之前不应出现。但在给定程序的情况下,当控件在main window
和DemoCompletedAsync
之间切换时,我实际上同时得到两个消息框。所有这些都是由于这一行:
Task task = DemoCompletedAsync();
您没有等待此任务,所以当指令指针到达实际线程时(此处为task.Run(()=>GetID());
),下一行立即执行。所以执行的下一行可以是MessageBox.Show(“返回的方法”)代码>或MessageBox.Show(“首次等待后”)代码>随机
但这里的要点是,你不能等待这个任务,因为你在构造函数中,它不能是异步的。此外,您不能像DemoCompletedAsync().wait()
那样等待此任务,因为您处于同步上下文中,将发生死锁
所以你应该这样称呼它:
DemoCompletedAsync().ConfigureAwait(false).GetAwaiter().GetResult();
并在GUI操作的DemoCompletedAsync
方法中使用Dispatcher.Invoke
,消息框“Task completed”(任务已完成)显示在刚刚创建但尚未等待的位置。因此,这一信息具有欺骗性。我建议在消息中包含任务.Status
。您实际上没有在等待任务,因为您的主方法没有等待它,因此消息将立即显示,您实际上在尝试做什么?“这只是一个任务的实验吗?”夏利是的,我正在试验任务。是,消息将立即显示。但它们应按顺序显示,即来自main窗口的消息或来自DemoCompletedAysnc的消息。为什么从MainWindow
显示一些消息,然后从DemoCompletedAsync
显示一些消息,然后再从MainWindow
显示一些消息。来自主窗口的消息应按顺序显示。应避免使用GetResult。ConfigureAwait很少是必需的。当您不想返回UI线程时,应该使用ConfigureAwait(false)
。例如,它应该用在存储库或与用户界面无关的东西中。@HenkHolterman:你说得对,Henk。我们应该尽可能避免阻塞线程,但我试图解释senarios,并根据它当前的结构回答这个问题。另外,始终建议使用ConfigureAwait(false)
来防止死锁+1您的回答中提到重组为Form\u Load
event@Michael:请参考我的上述评论。另请看我答案中的最后一行,这是您提到的解决方案UI@Arman,我的评论是@henkholtman comment。但是ConfigureAwait(false)
并不是为了防止死锁。我同意它可以做到这一点,但它不应该到处都是。您需要知道它的功能,因此需要了解上下文<代码>配置等待
仅适用于实际执行等待
的情况。GetWaiter'不算数。如果您在一个UI线程上,并且有一个await
语句,您通常会在await
之后返回UI线程。如果您等待的任务具有ConfigureAwait(false)
,它将返回另一个上下文,可能是一个新线程。