前言:我正在寻找一种解释,而不仅仅是一个解决方案。我已经知道了解决方案。
尽管花费了几天时间学习有关任务异步模式(TAP)、async和await的MSDN文章,但我仍对某些细节感到有些困惑。
我正在为Windows Store应用程序编写日志记录器,并且希望支持异步和同步记录。异步方法遵循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);
}
现在有对应的同步方法...
Version 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.
第三个版本:
嗯...Task.RunSynchronously
听起来很有前途。
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会导致程序冻结?任务对象存在问题吗?是否存在非明显的死锁?