Как распараллелить обработку очереди с сохранением порядка

Я работаю над программой C# для анализа видео. Основная операция:

  1. Захватить кадр видео
  2. Кадр процесса
  3. Показать рамку с аннотациями
  4. Сохранить результаты на диск
  5. Повторить

Если шаги 2–4 занимают больше времени, чем один кадр (30 мс), тогда кадры отбрасываются, что мне не нужно.

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

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

  1. Добавить рамку в BC# 1
  2. Возьмите кадр из BC# 1, обработайте, поместите результаты в BC# 2
  3. Возьмите результаты из BC# 2, добавьте аннотации и отобразите, сохраните на диск.

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

Например, я мог бы заставить каждый поток поместить результат в BlockingCollection, но если кадр № 2 завершит обработку до кадра № 1, результаты будут не по порядку.

  • Есть идеи, как реализовать это на C#?
  • Есть ли полезный класс или библиотека C#?
  • Что мне следует использовать для создания пула потоков, чтобы максимизировать производительность?

Обновлять

Результаты должны отображаться для пользователя в режиме, близком к реальному времени, поскольку программа предназначена для управления некоторыми приборами, поэтому последующая сортировка результатов, вероятно, невозможна.

В пакете nuget MassTransit есть система очереди сообщений InMemory. Вы можете опубликовать Message с параметром, и один из потребителей получит это сообщение и выполнит те же процессы. Однако операция, выполняемая по порядку, не имеет отношения к результату возврата. Если вы потребляете один за другим, ваш результат не теряет свойства порядка.

Adem Catamak 11.04.2018 12:07

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

Cake or Death 11.04.2018 12:10

@CalC Кадры должны обрабатываться по мере их поступления, потому что обработанный результат должен отображаться в пользовательском интерфейсе в реальном времени.

geometrikal 11.04.2018 14:25

Как далеко ты продвинулся? Вы пробовали использовать System.Reactive, также известный как Reactive Extensions? Пользуюсь им с хорошими результатами.

heltonbiker 13.11.2018 21:00
3
4
101
1

Ответы 1

Самый простой способ - использовать .AsParallel() из PLinQ:

var processedFrames = frames.AsParallel()
                            .AsOrdered()
                            .Select(Process)
                            .ToList();

Предполагая, что есть метод

ProcessedFrame Process(UnprocessedFrame original)
{
    // ...
}

Это обработает всю вашу последовательность, и в результате вы получите упорядоченную последовательность кадров результатов.

Это интересно, я не знал о PLinQ. Однако кадры должны обрабатываться по мере их поступления, поскольку результаты также должны отображаться для пользователя в реальном времени.

geometrikal 11.04.2018 14:26

Разве вам не нужно применять AsOrdered? Я думаю, что по умолчанию AsParallel не сохраняет порядок.

Evk 11.04.2018 14:45

Другие вопросы по теме