这实际上是我自己回答Circular dependency with cross-cutting concern
的回答的问题是否存在Parallel.ForEach
的变体,至少可以保证每个可能的任务都至少尝试,无论任何特定任务是否抛出异常?
我意识到我可以将每个任务包装在它自己的try
/ catch
/ finally
等中(直接或间接),也可以使用一些同步的容器来保存异常,或者一些东西,但这似乎是很多工作 - 有许多可能的评估解决方案 - 工作我认为可能更好的任务并行库来处理。
我在任务中抛出异常的试验似乎表明Parallel.ForEach
可能在中间中止并取消任何剩余的任务)。 {some enumerable}.AsParallel().ForAll({the task});
的情况似乎相似。我认为在某些情况下,中止剩余任务的策略 - 或者在创建剩余任务之前中止的策略 - 可能是完全可接受的行为。但是,有时,任务将会死亡,我们最好尝试尽可能多地执行任务,并跟踪哪些任务存活,哪些存活死亡。
我是这样看How to handle all unhandled exceptions when using Task Parallel Library?,但如果能回答我的问题,我不清楚。
http://blogs.msdn.com/b/pfxteam/archive/2009/05/31/9674669.aspx< =也可能有关系。
对我来说,这不是一个高优先级的问题,我只是想把它扔出去,以防其他人想要提供答案。
编辑:以防万一在代码中确实存在表明行为的错误,这里(也与其他问题有关)。我一直在LinqPad中运行它,有时我会看到所有WriteLine
结果,有时候我没有。请不要批评代码质量,我只是想知道我是否了解正在发生的事情。我怀疑可能存在[ThreadStatic]
修改过的变量。
static void Main() //Main(string[] args)
{
string[] messages = "this is a test. but it's going to be an issue!".Split(' ');
try{
messages.AsParallel().ForAll(Log);
} catch(AggregateException){
throw;
}
Console.ReadLine();
}
[ThreadStatic]
static bool _disable = false;
public static void Log(string message)
{
if (_disable)
{
return;
}
try {
_disable = true;
Console.WriteLine(GetPrefix() + message);
throw new Exception("bar");
} finally {
_disable = false;
}
}
public static string GetPrefix()
{
Log("Getting prefix!");
return "Prefix: ";
}
答案 0 :(得分:1)
首先,我认为当你谈论任务时会让人感到困惑。你所拥有的是使用Task
并行执行的循环迭代,但这并不意味着每次迭代都是一项任务。
其次,如果你真的这样做只是为了记录,你不可能获得任何性能提升,我不认为记录可以并行化。
现在,您可以做的是为循环的每次迭代手动创建单独的Task
,然后等待它们使用Task.WaitAll()
完成。这样,所有迭代都将被执行,如果其中一些失败,WaitAll()
将抛出一个包含所有迭代的AggregateException
。
var tasks = messages.Select(m => Task.Factory.StartNew(() => Log(m)));
Task.WaitAll(tasks.ToArray());
Parallel.ForEach()
或PLINQ的效率可能会低一些,但这对你来说可能没问题。如果没有,那么您必须使用您建议的try
- catch
方法。