使用Task.Wait()代码封装异步/等待IAsyncOperations有哪些风险?
我正在尝试将相当数量的现有同步代码移植到WinRT。作为其中的一部分,我遇到了一些问题,希望现有的代码能够实现某些操作是同步的 - 例如,文件I/O使用Task.Wait()代码封装异步/等待IAsyncOperations有哪些风险?
为适应这一现有代码中的WinRT的IAsyncOperation风格的API的工作中,我使用的扩展方法包裹IAsyncOperation类似的技术:
namespace Cirrious.MvvmCross.Plugins.File.WinRT
{
public static class WinRTExtensionMethods
{
public static TResult Await<TResult>(this IAsyncOperation<TResult> operation)
{
var task = operation.AsTask();
task.Wait();
if (task.Exception != null)
{
// TODO - is this correct?
throw task.Exception.InnerException;
}
return task.Result;
}
}
}
从MvvmCross WinRT ExtensionMethods - 与IAsyncAction
这些包装相似的方法似乎工作 - 他们允许我使用Async
方法同步代码,如:
public IEnumerable<string> GetFilesIn(string folderPath)
{
var folder = StorageFolder.GetFolderFromPathAsync(ToFullPath(folderPath)).Await();
var files = folder.GetFilesAsync().Await();
return files.Select(x => x.Name);
}
我知道这不是WinRT的精神,但我希望这些方法通常只能在后台线程中调用;而且我正在编写这个程序,目的是让我的代码跨平台兼容 - 包括尚未支持等待的平台 - 异步和/或尚未准备好跳转的开发人员。
所以......问题是:我使用这种类型的代码运行的风险是什么?
而作为第二个问题,有没有更好的方法可以实现代码重用,如File I/O?
我终于要回答这个....
答案是你不能真正做到这一点。
即使您尝试使用一些在其他的答案中建议的清洁方法,那么你最终还是打的异常,如果您尝试运行已承诺不会阻止任何线程的代码 - 例如如果您尝试在UI线程或线程池线程上运行。
所以......答案是,你只需要重新构建旧代码,以便它以某种方式异步!
首先,我觉得你的方法可能会被改写为:
public static TResult Await<TResult>(this IAsyncOperation<TResult> operation)
{
return operation.AsTask().Result;
}
调用Result
将同步等待,如果任务没有完成尚未。如果失败,它会抛出AgreggateException
。我认为像你这样抛出InnerException
是一个坏主意,因为它会覆盖异常的堆栈跟踪。
关于您的实际问题,我认为使用Wait()
与异步代码一起最大的危险是死锁。如果您在UI线程上启动了一些内部使用await
的操作,然后您在同一线程上使用Wait()
等待它,则会发生死锁。
这并不重要,如果你不是Wait()
在UI线程上,但你应该尽可能避免它,因为它违背了整个async
的想法。
感谢您的回答。关于异常问题,我试图让周围的代码期望像FileNotFoundException这样的异常 - 我真的不希望他们处理AggregatedException。总体而言,虽然,这是* *希望由我一个权宜之计 - 在较长时期内,我会要么重写API来使用基于行动
FWIW,他似乎更符合的await关键字,因为它得到抛出,而不是总的内部异常。 –
有很多很好的理由不这样做。例如见http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx
但是,如果你想这样做,使用GetResults()方法如下
public static TResult Await<TResult>(this IAsyncOperation<TResult> operation)
{
try
{
return operation.GetResults();
}
finally
{
operation.Close();
}
}
在任务中包装IAsyncOperation,如前所述svick,工作太多,但效率不高。
我无法得到这个工作。我尝试以下的代码: VAR夹= ApplicationData.Current.LocalFolder; var items = folder.CreateItemQuery()。GetItemsAsync()。Await(); 并得到: GetResults中发生了类型'System.InvalidOperationException'的异常 。更多信息: 一种方法被称为在一个意想不到的时间。 (来自HRESULT的异常:0x8000000E)。 AsTask()。结果奏效。 –
我有同样的问题,是我找到这篇文章的原因。 GetResults()不起作用,但AsTask()。结果工作正常 – noggin182
http://feedproxy.google.com/~r/AyendeRahien/~3/71OP6uo3bTQ/when-using-the-task-parallel-library-wait-is-a-bad-warning-sign –