C# 并行循环迭代方法

3

基本上,我的目标是让Parallel.ForEach在捕获到特定线程的错误时重复记录日志。

Parallel.ForEach(concurrentLogs, parallelOptions, log =>
  try{
   //Do work
   Console.WriteLine(log);
  }
  catch(Exception ex) {
  concurrentLogs.Enqueue(log); //repeat this log
  }
});

因为当我在调试代码时,如果线程捕获到错误(例如IO异常),它就不会再次输出同样的日志信息。
可能的解决方法是什么?

2
这取决于 concurrentLogs 的类型。如果它是 BlockingCollection,则需要使用 GetConsumingEnumerable() - Scott Chamberlain
1
你想要一直重复它,直到成功吗? - Farhad Jabiyev
你好 @ScottChamberlain,concurrentLogs 是一个 ConcurrentQueue。 - Anna P.
嗨@FarhadJabiyev,是的,你说得对! - Anna P.
2个回答

2
你正在枚举一个ConcurrentQueue,它将是集合的快照,并不反映你稍后Enqueue的项目。 一个快速的解决方案是在“foreach”中简单地重试:
Parallel.ForEach(concurrentLogs, parallelOptions, log =>
{
    void DoWork(string log)
    {
        //Do work
        Console.WriteLine(log);
    }

    try
    {
        DoWork(log);
    }
    catch(Exception ex) { // or loop and keep count
        DoWork(log);
    }
});

附注:正如在评论中指出的那样,这不是处理重试的最佳方法,您需要决定一种策略。Polly非常适合这种情况。

但是,这表明您不想要一个ConcurrentQueue,或者您没有有效地使用它。您可能想查看BlockingCollectionChannelActionBlock(TPL Dataflow)。


1
如果在 catch 块中再次失败会怎么样? - Eldar
1
那么你可以将其编写为循环、计数或任何你想要的策略。我在这里是来回答问题的,而不是编写可投入生产的代码。 - Stuart
1
@Eldar,“如果再次失败......”有点离题。OP可以简单地添加一个计数器,在最大重试后退出。关键问题是设计可能存在“缺陷”; OP应该考虑其他选择。Stuart提出了几个不错的选择 :) - paulsm4
3
@AnnaP. +1 另外,我可以建议您使用 Polly 进行重试逻辑。通过 nuget 安装它。然后在循环之外声明该策略:var retryPolicy = Policy.Handle<Exception>().RetryForever() 然后在循环内这样使用:retryPolicy.Execute(() => DoWork(log))) - Farhad Jabiyev
1
非常感谢您的快速回复,@Stuart :) - Anna P.
显示剩余2条评论

1
            Parallel.ForEach(concurrentLogs, parallelOptions, log => { 
            bool sucess = true;
            do
            {
                try
                {
                    //Do work
                    Console.WriteLine(log);
                }
                catch (Exception ex)
                {
                    sucess = false;
                }
            }while(!sucess)

        });

2
@Eldar,内存出了什么问题吗?你只是重复操作而已。它可能缺少重试策略(例如“我需要在尝试之间等待多长时间”、“我如何报告错误”以及“在多少次失败后我需要停止尝试”),但总的来说,这似乎是实现此目的的正确方式。 - Yeldar Kurmangaliyev
1
你的代码第一版在尝试处理日志时,每次失败都会将另一个日志加入队列。当 while 循环完成时,日志已经被处理,catch 块中排队的日志将是多余的。但这个版本也可以,正如你所说,while 循环可能存在风险,我更喜欢这个答案。你应该将你的评论内容添加到你的答案中。 - Eldar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接