将使用任务并行库尝试任何保证所有任务的方法吗?

时间:2013-07-18 19:57:37

标签: .net multithreading exception-handling task-parallel-library

这实际上是我自己回答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: ";
}

1 个答案:

答案 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方法。