【发布时间】:2015-09-11 22:12:09
【问题描述】:
我的应用程序中有 3 个任务负责从数据库中获取数据。
到现在我已经一个接一个地执行了所有的任务。如果第一次完成并有结果,那么这是我的数据,如果现在我开始第二个任务并再次检查。
最近我发现我可以使用Task.Factory.ContinueWhenAny 启动多个任务并在其中一个任务完成时继续。如果我的所有任务都没有抛出任何异常,这可以正常工作,但如果任何任务失败,我将无法获得我想要的结果。
例如:
var t1 = Task.Factory.StartNew(() =>
{
Thread.Sleep(5000);
return 1;
});
var t2 = Task.Factory.StartNew(() =>
{
Thread.Sleep(2000);
throw new Exception("My error");
return 2;
});
var t3 = Task.Factory.StartNew(() =>
{
Thread.Sleep(4000);
return 3;
});
Task.Factory.ContinueWhenAny(new[] {t1, t2,t3}, (t) =>
{
Console.WriteLine(t.Result);
});
此代码启动 3 个任务并等待其中一个任务完成。
因为t2 在 2 秒后抛出异常,所以它是 ContinueWhenAny 中可用的异常。
从上面的代码中,我想在t.Result 中获得 3。
是否只有在任务成功完成后才能继续?类似Task.Factory.ContinueWhenAnyButSkipFailedTasks
编辑 1 这是我现在基于@Nitram 回答的解决方案:
var t1 = Task.Factory.StartNew(() =>
{
var rnd = new Random();
Thread.Sleep(rnd.Next(5,15)*1000);
throw new Exception("My error");
return 1;
});
var t2 = Task.Factory.StartNew(() =>
{
Thread.Sleep(2000);
throw new Exception("My error");
return 2;
});
var t3 = Task.Factory.StartNew(() =>
{
throw new Exception("My error");
return 3;
});
var tasks = new List<Task<int>> { t1, t2, t3 };
Action<Task<int>> handler = null;
handler = t =>
{
if (t.IsFaulted)
{
tasks.Remove(t);
if (tasks.Count == 0)
{
throw new Exception("No data at all!");
}
Task.Factory.ContinueWhenAny(tasks.ToArray(), handler);
}
else
{
Console.WriteLine(t.Result);
}
};
Task.Factory.ContinueWhenAny(tasks.ToArray(), handler);
我现在需要的是当所有任务都抛出异常时如何抛出异常?
也许这可以更改为返回任务的单一方法 - 类似于子任务?
【问题讨论】:
-
我认为您需要编写自己的 Task.WhenAny 版本,该版本采用 Func
指定此特定任务完成是否应该完成WhenAny。
标签: c# async-await task-parallel-library .net-4.5