.jpg)
前言:我在寻找一个解释,而不仅仅是一个解决方案。我已经知道解决方案了。
尽管我花了几天时间研究 MSDN 关于基于任务的异步模式 (TAP)、异步和等待的文章,但我仍然对一些更精细的细节感到有些困惑。
我正在为 Windows 应用商店应用编写记录器,并且希望同时支持异步和同步日志记录。异步方法遵循 TAP,同步方法应该隐藏所有这些,并且外观和工作方式与普通方法相同。
这是异步日志记录的核心方法:
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);
}
现在相应的同步方法…
版本1:
private void WriteToLog(string text)
{
Task task = WriteToLogAsync(text);
task.Wait();
}
这看起来是正确的,但它不起作用。整个程序永远冻结。
版本2:
嗯。。也许任务没有开始?
private void WriteToLog(string text)
{
Task task = WriteToLogAsync(text);
task.Start();
task.Wait();
}
这抛出InvalidOperationException: Start may not be called on a promise-style task.
版本3:
嗯。。 听起来很有希望。Task.RunSynchronously
private void WriteToLog(string text)
{
Task task = WriteToLogAsync(text);
task.RunSynchronously();
}
这抛出InvalidOperationException: RunSynchronously may not be called on a task not bound to a delegate, such as the task returned from an asynchronous method.
版本 4(解决方案):
private void WriteToLog(string text)
{
var task = Task.Run(async () => { await WriteToLogAsync(text); });
task.Wait();
}
这行得通。因此,2 和 3 是错误的工具。但是1?1 有什么问题,4 有什么区别?是什么让 1 导致冻结?任务对象有问题吗?是否存在不明显的僵局?

异步方法内部正在尝试返回到 UI 线程。await
由于 UI 线程正忙于等待整个任务完成,因此会出现死锁。
移动异步调用可解决此问题。
由于异步调用现在在线程池线程上运行,因此它不会尝试返回到 UI 线程,因此一切正常。Task.Run()
或者,您可以在等待内部操作之前调用,使其返回到线程池而不是 UI 线程,从而完全避免死锁。StartAsTask().ConfigureAwait(false)

从同步代码调用代码可能非常棘手。async
我在我的博客上解释了这种僵局的全部原因。简而言之,有一个“上下文”默认保存在每个方法的开头,并用于恢复该方法。await
因此,如果在 UI 上下文中调用此函数,则在 完成时,该方法会尝试重新进入该上下文以继续执行。遗憾的是,使用 (或) 的代码将阻塞该上下文中的线程,因此该方法无法完成。awaitasyncWaitResultasync
避免这种情况的准则是:
ConfigureAwait(continueOnCapturedContext: false)asyncasyncawaitResultWait如果你的方法本质上是异步的,那么你(可能)不应该公开同步包装器。

这是我所做的
private void myEvent_Handler(object sender, SomeEvent e)
{
// I dont know how many times this event will fire
Task t = new Task(() =>
{
if (something == true)
{
DoSomething(e);
}
});
t.RunSynchronously();
}
工作良好且不会阻塞 UI 线程
模板简介:该模板名称为【C#同步等待异步操作,为什么 Wait() 会在这里冻结程序】,大小是暂无信息,文档格式为.编程语言,推荐使用Sublime/Dreamweaver/HBuilder打开,作品中的图片,文字等数据均可修改,图片请在作品中选中图片替换即可,文字修改直接点击文字修改即可,您也可以新增或修改作品中的内容,该模板来自用户分享,如有侵权行为请联系网站客服处理。欢迎来懒人模板【C#】栏目查找您需要的精美模板。