Цикл Parallel.Foreach, несовместимое поведение с явным оператором throw - PullRequest
0 голосов
/ 13 сентября 2018

Создал простую программу с использованием Linqpad, где я выбрасываю исключение в цикле Parallel Foreach, которое в идеале должно быть перехвачено в вызывающей программе как Aggregate Exception, но когда я явно выбрасываю исключение, оно иногда пропускает несколькоисключения на случайной основе.Я не могу понять поведение, любой, кто может объяснить:

void Main()
{
    try
    {
      var intList = new List<int> {1,2,3,4,5,6};

      Parallel.ForEach(intList, i => Test1(i));
    }
    catch (AggregateException aggregateException)
    {
        foreach (var ex in aggregateException.Flatten().InnerExceptions)
        {
            ex.Message.Dump();
        }
    }
}

public void Test1(int i)
{
    try
    {
        if (i % 2 != 0)
            throw new Exception($"{i} - Odd value exception");

    }
    catch(Exception ex)
    {
        ex.Message.Dump();
        throw;
    }
}

public void Test2(int i)
{
        if (i % 2 != 0)
            throw new Exception($"{i} - Odd value exception");
}

public void Test3(int i)
    {
        try
        {
            if (i % 2 != 0)
                throw new Exception($"{i} - Odd value exception");

        }
        catch(Exception ex)
        {
            ex.Message.Dump();
        }
    }

Подробности:

  1. Есть две версии Test, одна с явным Try Catch и другая без
  2. Оба имеют схожее противоречивое поведение в той мере, в которой в Test1 даже локальный try catch не выводит значение
  3. Может существовать третья версия Test3, которая всегда работает, так как исключение явно не выбрасываетсяпараллельного цикла
  4. Dump это вызов печати linqpad замените его на Console.WriteLine в visual studio

Здесь есть опция определения здесь , котораясобирает все исключения в ConcurrentQueue и генерирует их позже как агрегированное исключение, но почему текущий код не работает должным образом, я не очень уверен.В этом случае мы ожидаем, что Output будет:

1 - Odd value exception
3 - Odd value exception
5 - Odd value exception

, но некоторые из них пропускаются случайным образом, что также в простой программе, гораздо больше промахов в сложной программе, которая выполняет гораздо больше работы

1 Ответ

0 голосов
/ 13 сентября 2018

Это вполне ожидаемое поведение.

См. документы ,

необработанное исключение приводит к немедленному завершению цикла

Когда вы выбрасываете исключение, новые задачи не будут запланированы.

Таким образом, поведение будет непредсказуемым. Вы не имеете права ожидать выполнения всех подзадач. Это не контракт цикла Parallel.For.

Разница будет намного понятнее, когда вы добавите больше элементов в список источников. Выходные данные всегда будут отображать ряд исключений в окрестности ThreadPool.MinThreads.

...