Цикл Parallel.Foreach, несовместимое поведение с явным оператором throw

2

Создал простую программу с использованием 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 на визуальной студии

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

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

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

  • 0
    @MickyD MickyD Нет, я не знаю, это чисто для изучения, иначе шаблон в ссылке MSDN хорош
  • 0
    Отлично. Спасибо
Показать ещё 1 комментарий
Теги:
task-parallel-library
parallel.foreach

1 ответ

3
Лучший ответ

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

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

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

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

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

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

Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню