【发布时间】:2014-07-09 03:05:29
【问题描述】:
我有时会使用一组任务,为了确保它们都在等待中,我使用了这种方法:
public async Task ReleaseAsync(params Task[] TaskArray)
{
var tasks = new HashSet<Task>(TaskArray);
while (tasks.Any()) tasks.Remove(await Task.WhenAny(tasks));
}
然后这样称呼它:
await ReleaseAsync(task1, task2, task3);
//or
await ReleaseAsync(tasks.ToArray());
但是,最近我注意到一些奇怪的行为,并开始查看 ReleaseAsync 方法是否存在问题。我设法将它缩小到这个简单的演示,如果你包含System.Threading.Tasks,它会在 linqpad 中运行。它也可以在控制台应用程序或 asp.net mvc 控制器中稍作修改。
async void Main()
{
Task[] TaskArray = new Task[]{run()};
var tasks = new HashSet<Task>(TaskArray);
while (tasks.Any<Task>()) tasks.Remove(await Task.WhenAny(tasks));
}
public async Task<int> run()
{
return await Task.Run(() => {
Console.WriteLine("started");
throw new Exception("broke");
Console.WriteLine("complete");
return 5;
});
}
我不明白为什么异常永远不会出现在任何地方。我会想到,如果等待带有异常的任务,它会抛出。我可以通过用一个简单的 for each 替换 while 循环来确认这一点,如下所示:
foreach( var task in TaskArray )
{
await task;//this will throw the exception properly
}
我的问题是,为什么显示的示例没有正确抛出异常(它永远不会出现在任何地方)。
【问题讨论】:
-
有什么理由不使用
Task.WhenAll? -
@PauloMorgado - 是的,这些与托管资源相关联,我想在它们可用时释放它们,而不是等待它们全部完成然后释放。
-
此资源发布不在您发布的代码上,对吧?并且托管资源“释放自己”。
-
@PauloMorgado - 版本不在代码中,正确。至于托管资源说明,抱歉打错了,它应该读取“非托管”,因为它的生命周期由 using 块决定并继承 IDisposable。
标签: c# .net exception async-await task