我在寻找一个解释,而不仅仅是一个解决方案。我已经知道了解决方案。尽管花了几天时间研究有关基于任务的异步模式(TAP),异步和等待的MSDN文章,但我对某些更详细的信息仍然感到困惑。我正在为Windows Store Apps编写记录器,并且希望同时支持异步和同步记录。异步方法遵循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冻结?任务对象有问题吗?有没有明显的僵局?
3 回答
凤凰求蛊
TA贡献1825条经验 获得超4个赞
async从同步代码中调用代码可能非常棘手。
我在博客上解释了造成这种僵局的全部原因。简而言之,每个上下文的开头都有一个默认保存的“上下文”,await用于恢复该方法。
因此,如果在UI上下文中调用await此async方法,则在完成时,该方法将尝试重新输入该上下文以继续执行。不幸的是,使用Wait(或Result)的代码将在该上下文中阻塞线程,因此该async方法无法完成。
避免这种情况的准则是:
使用ConfigureAwait(continueOnCapturedContext: false)尽可能多地。这使您的async方法可以继续执行而不必重新输入上下文。
一直使用async。使用await代替Result或Wait。
如果您的方法自然是异步的,那么(可能)您不应该公开同步包装器。
- 3 回答
- 0 关注
- 845 浏览
添加回答
举报
0/150
提交
取消