Я пишу приложение WPF, которое обрабатывает поток данных изображения с ИК-камеры.Приложение использует библиотеку классов для таких шагов обработки, как изменение масштаба или раскраска, которые я также пишу сам.Этап обработки изображения выглядит примерно так:
ProcessFrame(double[,] frame)
{
int width = frame.GetLength(1);
int height = frame.GetLength(0);
byte[,] result = new byte[height, width];
Parallel.For(0, height, row =>
{
for(var col = 0; col < width; ++col)
ManipulatePixel(frame[row, col]);
});
}
Кадры обрабатываются задачей, которая выполняется в фоновом режиме.Проблема в том, что в зависимости от того, насколько дорогостоящим является конкретный алгоритм обработки (ManipulatePixel()
), приложение больше не может справиться с частотой кадров камеры.Однако я заметил, что, несмотря на то, что я использую параллельные циклы for, приложение просто не будет использовать весь доступный ЦП - на вкладке производительности диспетчера задач показано, что загрузка ЦП составляет около 60-80%.
Я использовалте же алгоритмы обработки в C ++ ранее, используя циклы concurrency::parallel_for
из библиотеки параллельных шаблонов.Код C ++ использует весь процессор, который он может получить, как я и ожидал, и я также попытался PInvoking
C ++ DLL из моего кода C #, выполняя тот же алгоритм, который работает медленно в библиотеке C # - он также использует весь процессордоступная мощность, использование процессора практически на 100% практически все время, и нет никаких проблем с тем, чтобы не отставать от камеры.
Аутсорсинг кода в C ++ DLL с последующим перенаправлением его обратно в C # является дополнительнымхлопот, которых я, конечно, предпочел бы избежать.Как мне сделать, чтобы мой код C # фактически использовал весь потенциал процессора?Я попытался увеличить приоритет процесса следующим образом:
using (Process process = Process.GetCurrentProcess())
process.PriorityClass = ProcessPriorityClass.RealTime;
, который имеет эффект, но только очень маленький.Я также попытался установить степень параллелизма для циклов Parallel.For()
следующим образом:
ParallelOptions parallelOptions = new ParallelOptions();
parallelOptions.MaxDegreeOfParallelism = Environment.ProcessorCount;
, а затем передать это в цикл Parallel.For()
, это никак не повлияло, но я полагаю, что это не удивительно, посколькунастройки по умолчанию уже должны быть оптимизированы.Я также попытался установить это в конфигурации приложения:
<runtime>
<Thread_UseAllCpuGroups enabled="true"></Thread_UseAllCpuGroups>
<GCCpuGroup enabled="true"></GCCpuGroup>
<gcServer enabled="true"></gcServer>
</runtime>
, но на самом деле это заставляет его работать еще медленнее.
EDIT : Блок кода ProcessFrame Iцитируется изначально было на самом деле не совсем правильно.То, что я делал в то время, было:
ProcessFrame(double[,] frame)
{
byte[,] result = new byte[frame.GetLength(0), frame.GetLength(1)];
Parallel.For(0, frame.GetLength(0), row =>
{
for(var col = 0; col < frame.GetLength(1); ++col)
ManipulatePixel(frame[row, col]);
});
}
Извините за это, я перефразировал код в то время, и я не осознавал, что это настоящая ловушка, которая дает разные результаты.С тех пор я изменил код на то, что я изначально написал (то есть переменные ширины и высоты, установленные в начале функции, и свойства длины массива запрашиваются только один раз, а не в условных выражениях цикла for).Спасибо @Seabizkit, твой второй комментарий вдохновил меня попробовать это.Фактически изменение уже делает код работающим заметно быстрее - я не осознавал этого, потому что C ++ не знает двумерных массивов, поэтому мне все равно пришлось передавать размеры в пикселях как отдельные аргументы.Достаточно ли быстро, как есть, я пока не могу сказать.
Также спасибо за другие ответы, они содержат много вещей, которые я пока не знаю, но здорово знать, на что мне смотретьза.Я обновлю, как только достигну удовлетворительного результата.