【问题标题】:Parallel.ForEach:Break 和 ParallelLoopState.LowestBreakIteration。该怎么办?
【发布时间】:2022-01-23 09:14:17
【问题描述】:

在 microsoft 上的这个 article 中,在 Parallel.For 的示例中,方法中有一个 Break 调用和对 ShouldExitCurrentIteration 和 LowestBreakIteration 等属性的处理,方式如下:

    if (state.ShouldExitCurrentIteration)
    {
       if (state.LowestBreakIteration < i)
       return;
    }

LowestBreakIteration 存储调用 Break 方法的最小迭代次数。 此外,此属性可以存储内部生成的索引的值,例如在方法 Parallel.ForEach 的情况下(source on docs microsoft)

问题在 Parallel.ForEach 的情况下,我应该如何处理属性 LowestBreakIteration,我应该如何使用它以及我应该与什么进行比较?

我很容易地用 Break for Parallel.For 重复了这个例子,但是我不知道如何在用 Break for Parallel.ForEach 的例子中使用属性 LowestBreakIteration。

using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            //Parallel.For
            void MyMethodForParallelForBreak(int i, ParallelLoopState MyParallelLoopState)
            {
                Console.WriteLine($"Start {i}");

                if (MyParallelLoopState.ShouldExitCurrentIteration)
                {
                    if (MyParallelLoopState.LowestBreakIteration < i) //Processing LowestBreakIteration here
                    {
                        Console.WriteLine($"Current {i}. Return: LowestBreakIteration {MyParallelLoopState.LowestBreakIteration} < {i}");
                        return;
                    }
                }

                if (MyParallelLoopState.LowestBreakIteration != null)
                {
                    Console.WriteLine($"Current {i}. LowestBreakIteration {MyParallelLoopState.LowestBreakIteration}");
                }

                if (i > 5)
                {
                    MyParallelLoopState.Break();

                    Console.WriteLine($"Current {i}. Break");
                }

                Console.WriteLine($"End {i}");
            }

            Parallel.For(1, 11, MyMethodForParallelForBreak);

            Console.WriteLine("\n");



            //Parallel.ForEach
            void MyMethodForParallelForEachBreak(KeyValuePair<string, string> MyKeyValuePair, ParallelLoopState MyParallelLoopState)
            {
                Console.WriteLine($"Start {MyKeyValuePair.Key}");

                if (MyParallelLoopState.ShouldExitCurrentIteration)
                {
                    if (MyParallelLoopState.LowestBreakIteration < ) //Error. Unknown. Processing LowestBreakIteration here
                    {
                        Console.WriteLine($"Current {MyKeyValuePair.Key}. Return: LowestBreakIteration {MyParallelLoopState.LowestBreakIteration} < Unknown");
                        return;
                    }
                }

                if (MyParallelLoopState.LowestBreakIteration != null)
                {
                    Console.WriteLine($"Current {MyKeyValuePair.Key}. LowestBreakIteration {MyParallelLoopState.LowestBreakIteration}");
                }

                if (MyKeyValuePair.Value == "a")
                {
                    MyParallelLoopState.Break();

                    Console.WriteLine($"Current {MyKeyValuePair.Key}. Break");
                }

                Console.WriteLine($"End {MyKeyValuePair.Key}");
            }


            Dictionary<string, string> MyDictionaryForStringAndString = new Dictionary<string, string>();

            MyDictionaryForStringAndString.Add("a1", "abc");
            MyDictionaryForStringAndString.Add("a2", "ab");
            MyDictionaryForStringAndString.Add("a3", "a");
            MyDictionaryForStringAndString.Add("a4", "abc");
            MyDictionaryForStringAndString.Add("a5", "ab");
            MyDictionaryForStringAndString.Add("a6", "a");
            MyDictionaryForStringAndString.Add("a7", "abc");
            MyDictionaryForStringAndString.Add("a8", "ab");
            MyDictionaryForStringAndString.Add("a9", "a");
            MyDictionaryForStringAndString.Add("a10", "abc");

            Parallel.ForEach(MyDictionaryForStringAndString, MyMethodForParallelForEachBreak);
        }
    }
}

【问题讨论】:

    标签: c# .net multithreading parallel-foreach


    【解决方案1】:

    可以查看ShouldExitCurrentIteration属性看看是否需要退出并行foreach:

    if (state.ShouldExitCurrentIteration) {
      // some other thread called state.Break()
      return;
    }
    

    【讨论】:

    • 我可能根本不检查任何东西,Stop 和 Break 只会停止创建新任务并设置属性,在某些时候任务会停止创建。但是为了更合理地利用资源,需要在方法内部提供逻辑。我试图了解开发人员为什么要更改 LowestBreakIteration 属性以及如何使用它。 LowestBreakIteration 存在,但您不需要使用它的答案,不适合我,我怀疑 Parallel.ForEach 中属性 LowestBreakIteration 的值无缘无故改变。
    【解决方案2】:

    如果您想在 Parallel.Foreach 循环中检查 LowestBreakIteration,则有一个带有 Action&lt;TSource, ParallelLoopState, long&gt; 参数的 overload。其中long-value代表索引。

    我会注意到 LowestBreakIteration / ShouldExitCurrentIteration 的使用对我来说似乎很深奥。我能想象的唯一用例是每次迭代都涉及多个昂贵的操作,因此您希望尽快退出,并且您仍然希望在调用中断的迭代之前处理所有项目。

    我肯定从来没有觉得需要这样的功能,虽然对于确实需要它的人来说拥有它可能是件好事,但我不会担心。

    【讨论】:

    • 非常感谢!这正是我所需要的。
    猜你喜欢
    • 2021-10-01
    • 1970-01-01
    • 2019-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-07
    • 2017-03-03
    • 2021-08-06
    相关资源
    最近更新 更多