等待任务与Task.GetAwaiter

时间:2018-05-15 21:56:20

标签: c# asynchronous async-await task

为什么以下示例不起作用(两个文本同时更改):

Task.Run(async () =>
        {
            await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
            {
                await Task.Delay(2000);
                textnew1.Text = "Dispatched";
            });
            await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
            {
                await Task.Delay(2000);
                textnew2.Text = "BackgroundTask";
            });
        });

而这一个(第一个文本更改,第二个文本在两秒后跟随):

Task.Run(async () =>
        {
            await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            {
                Task.Delay(2000).GetAwaiter().GetResult();
                textnew1.Text = "Dispatched";
            });
            await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            {
                Task.Delay(2000).GetAwaiter().GetResult();
                textnew2.Text = "BackgroundTask";
            });
        });

为什么第一个代码中没有等待Task.Delayawait Task.DelayTask.Delay().GetAwaiter().GetResult()之间有什么区别?

2 个答案:

答案 0 :(得分:3)

您有一个async void,您的第一个代码示例等同于

Task.Run(async () =>
        {
            await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, new DispatchedHandler(FirstTask));
            await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, new DispatchedHandler(SecondTask));
        });

private async void FirstTask()
{
    await Task.Delay(2000);
    textnew1.Text = "Dispatched";
}
private async void SecondTask()
{
    await Task.Delay(2000);
    textnew2.Text = "BackgroundTask";
}

由于DispatchedHandler的签名是public delegate void DispatchedHandler(),因此您无法使用它返回任务。当您执行async void时,RunAsync会在await Task.Delay()被点击后认为任务已完成。

答案 1 :(得分:1)

正如Scott's Answer正确解释的那样,即使您正在等待延迟,您的异步版本仍在继续的原因是因为Displatcher.RunAsync接受void委托。至于适当的解决方案,我强烈建议避免在代码中使用所有async lambdas。 Task.Run确实理解如何处理Task返回方法,但是你仍然通过构建代码来使自己做很多事情,特别是你没有利用这个事实async方法捕获同步上下文,这样您就不必首先将代码手动编组到UI线程。

您可以将答案重写为:

await Task.Delay(2000);
textnew1.Text = "Dispatched";
await Task.Delay(2000);
textnew2.Text = "BackgroundTask";

如果您有一些长期运行的非UI CPU绑定工作要做,并且要完成UI更新,而不是将 while thing 放在带有调度程序的Task.Run lambda中整个调用只需使用Task.Run来专门调用非UI CPU绑定的工作,然后在等待它之后做任何需要在UI上下文中运行的内容:

await Task.Delay(2000);
textnew1.Text = "Dispatched";
await Task.Run(() => SomeBackroundWork());
textnew2.Text = "BackgroundTask";