同步等待异步操作,为什么等待()这里冻结计划 [英] Synchronously waiting for an async operation, and why does Wait() freeze the program here

查看:759
本文介绍了同步等待异步操作,为什么等待()这里冻结计划的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

preface :我在寻找一个解释,而不仅仅是一个解决方案。我已经知道了解决方案。

Preface: I'm looking for an explanation, not just a solution. I already know the solution.

尽管已经花了好几天研究有关基于任务的异步模式(TAP),异步MSDN文章和等待,我还是有点困惑的一些细节了。

Despite having spent several days studying MSDN articles about the Task-based Asynchronous Pattern (TAP), async and await, I'm still a bit confused about some of the finer details.

我正在写一个记录器的Windows应用商店的应用程序,我想支持异步和同步记录。异步方法遵循TAP,同步的人应隐藏了这一切,并期待携手像普通的方法。

I'm writing a logger for Windows Store Apps, and I want to support both asynchronous and synchronous logging. The asynchronous methods follow the TAP, the synchronous ones should hide all this, and look and work like ordinary methods.

这是异步日志的核心方法:

This is the core method of asynchronous logging:

private async Task WriteToLogAsync(string text)
{
    StorageFolder folder = ApplicationData.Current.LocalFolder;
    StorageFile file = await folder.CreateFileAsync("log.log",
        CreationCollisionOption.OpenIfExists);
    await FileIO.AppendTextAsync(file, text,
        Windows.Storage.Streams.UnicodeEncoding.Utf8);
}

现在对应的同步方法...

Now the corresponding synchronous method...

版本1

private void WriteToLog(string text)
{
    Task task = WriteToLogAsync(text);
    task.Wait();
}

这是正确的,但它不工作。整个程序没有响应,直到永远。

This looks correct, but it does not work. The whole program freezes forever.

版本2

嗯..也许任务未启动?

Hmm.. Maybe the task was not started?

private void WriteToLog(string text)
{
    Task task = WriteToLogAsync(text);
    task.Start();
    task.Wait();
}

这将引发 InvalidOperationException异常:开始可能不叫上一个承诺式的任务

第3版:

嗯.. Task.RunSynchronously 听起来有希望的。

Hmm.. Task.RunSynchronously sounds promising.

private void WriteToLog(string text)
{
    Task task = WriteToLogAsync(text);
    task.RunSynchronously();
}

这将引发 InvalidOperationException异常:RunSynchronously不能称为一个任务未绑定到委托,如任务从一个异步方法返回

版本4(解决方案):

private void WriteToLog(string text)
{
    var task = Task.Run(async () => { await WriteToLogAsync(text); });
    task.Wait();
}

这工作。所以,2和3是错误的工具。但是,1?有什么问题1,什么是差价4?是什么让1引起冻结?有一些问题,任务目标?是否有一个非显而易见的僵局?

This works. So, 2 and 3 are the wrong tools. But 1? What's wrong with 1 and what's the difference to 4? What makes 1 cause a freeze? Is there some problem with the task object? Is there a non-obvious deadlock?

请帮助我了解。

推荐答案

等待里面,你的异步方法试图回来到UI线程。

The await inside your asynchronous method is trying to come back to the UI thread.

由于UI线程繁忙等待整个任务完成,你有一个僵局。

Since the UI thread is busy waiting for the entire task to complete, you have a deadlock.

移动异步调用 Task.Run()解决了这个问题。
由于异步调用现在在一个线程池线程运行的,它并不试图回来到UI线程,因此,一切正常。

Moving the async call to Task.Run() solves the issue.
Because the async call is now running on a thread pool thread, it doesn't try to come back to the UI thread, and everything therefore works.

另外,你可以调用 StartAsTask()。ConfigureAwait(假)等待内部操作,使其回到线程池,而不是UI线程,避免前僵局完全。

Alternatively, you could call StartAsTask().ConfigureAwait(false) before awaiting the inner operation to make it come back to the thread pool rather than the UI thread, avoiding the deadlock entirely.

请参阅<一href="http://ermau.com/avoiding-callbacks-to-the-ui-thread-with-async-and-winrt/">http://ermau.com/avoiding-callbacks-to-the-ui-thread-with-async-and-winrt/

这篇关于同步等待异步操作,为什么等待()这里冻结计划的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆