странное поведение параллельного foreach

#c# #parallel.foreach

#c# #parallel.foreach

Вопрос:

Я закодировал запуск более или менее следующей конструкции — и когда ParallelRunner получает функцию делегирования TestFunc, она зависает, однако, если вместо предоставления делегата я пишу функцию явно внутри метода ParallelRunner, она работает нормально.

Обратите внимание, что этот точный метод тестирования работает, но очень похожий код, выполняемый в IIS (в фоновом потоке), завершается сбоем, и как только я удаляю делегат TestFunc и явно записываю его код в ParallelRunner или даже вызываю TestCondition напрямую ( без делегата), он работает нормально.

Есть идеи, что может вызвать это странное поведение?

   interface I { }

        class A : I { }
        class B :I { }

        [TestMethod]
        public void TestParallelWithDelegate()
        {
            var list = new List<I>();

            for (int i = 0; i < 300000; i  )
            {
                if (i % 2 == 0)
                {
                    list.Add(new A());

                }
                else
                {
                    list.Add(new B());
                }


            }

            var bag = new ConcurrentBag<I>();

            Func<I, bool> testFunc = TestCondition;

            ParallelRunner(list,bag,testFunc);

            Console.WriteLine($"terminated with delegate bag size = {bag.Count}");

        }
        private static bool TestCondition(I i)
        {
            return !(i is A);
        }


        void ParallelRunner(List<I> list, ConcurrentBag<I> bag, Func<I,bool> testFunc = null)
        {
            Parallel.ForEach(list, new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount * 3 },
                x =>
                {
                    if (testFunc == null || testFunc(x))
                    {
                        bag.Add(x);

                    }
                });

        }
 

Комментарии:

1. Возможно, вы теряете свою переменную, хотя я не очень часто работаю с parallel для каждого. Попробуйте это: над вашей параллелью. ForEach, добавьте, var testFunc2 = testFunc; а затем измените свой цикл для выполнения testFunc2 . Имеет ли это значение?

2. В реальном коде TestFunc является статическим методом в некотором классе, так как же он мог быть потерян? Я все равно попробую и посмотрю.. Спасибо

3. Я думаю, что это связано с тем, как долго testFunc существует переменная, и правильно указывает на ваш статический метод. Возможно, это не ваш случай — вы попробовали мое предложение?

4. Да, он зависает.. Я думаю, это может быть связано с тем фактом, что делегат, отправленный как TestFunc, является статическим методом в классе, статический конструктор которого содержит приведенный выше код… Когда я отлаживаю, я вижу, что действительно это работает до определенного момента, но затем останавливается. Интересно, почему этот статический метод находится в пределах области видимости часть времени, а затем останавливается, как вы предлагаете. есть идеи?

5. Если он просто зависает, проверьте это — devblogs.microsoft.com/pfxteam/static-constructor-deadlocks