Parallel.ForEach:中断并ParallelLoopState.LowestBreakIteration。怎么办?

Parallel.ForEach: Break and ParallelLoopState.LowestBreakIteration. What to do about it?

In this article on docs microsoft,在方法中的例子Parallel.For中,有一个Break调用和对ShouldExitCurrentIteration和LowestBreakIteration等属性的处理如下:

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

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

的情况下

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

我很容易地用 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);
        }
    }
}

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

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

如果您想在 Parallel.Foreach 循环中检查 LowestBreakIteration,可以使用带有 Action<TSource, ParallelLoopState, long> 参数的 overload。其中 long-value 代表索引。

我会注意到 LowestBreakIteration / ShouldExitCurrentIteration 的用法对我来说似乎非常深奥。我能想象的唯一用例是每次迭代都涉及多个昂贵的操作,所以你想尽快退出, 你仍然想在调用的迭代之前处理所有项目休息。

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