Многопоточная обработка изображений в C++

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

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

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

11
задан Community 23 May 2017 в 12:13
поделиться

14 ответов

Если Ваш компилятор поддерживает OpenMP (я знаю, что VC ++ 8.0 и 9.0 делает, как делает gcc), он может сделать вещи как это намного легче сделать.

Вы только хотите сделать много потоков - существует точка убывающей доходности, где добавление новых потоков замедляет вещи, поскольку Вы начинаете получать все больше контекстных переключений. В какой-то момент использование слишком многих потоков может на самом деле сделать параллельную версию медленнее, чем просто использование линейного алгоритма. Оптимальное количество потоков является функцией количества доступных CPU/ядер, и процент времени, которое каждый поток проводит заблокированный на вещах как ввод-вывод. Смотрите на эту статью Herb Sutter для некоторого обсуждения параллельного увеличения производительности.

OpenMP позволяет Вам легко адаптировать количество потоков, созданных к количеству доступных центральных процессоров. Используя его (особенно в случаях обработки данных) часто включает просто включение некоторых #pragma omps в существующем коде и разрешении потокам создания дескриптора компилятора и синхронизации.

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

Для OpenMP нет никакой потребности сделать что-либо специальное до функторов / функциональные объекты. Запишите это, какой бы ни путь имеет большую часть смысла Вам. Вот пример обработки изображений от Intel (преобразовывает rgb в шкалу полутонов):

#pragma omp parallel for
for (i=0; i < numPixels; i++)
{
   pGrayScaleBitmap[i] = (unsigned BYTE)
       (pRGBBitmap[i].red * 0.299 +
        pRGBBitmap[i].green * 0.587 +
        pRGBBitmap[i].blue * 0.114);
}

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

10
ответ дан 3 December 2019 в 02:31
поделиться

Существует другая опция использования блока для оптимизации. Теперь, один захватывающий проект для динамической генерации кода является softwire (который датируется некоторое время - вот сайт исходного проекта). Это было разработано Nick Capens и превратилось теперь коммерчески в доступный swiftshader. Но ответвление исходного softwire все еще доступно на gna.org.

Это могло служить введением в его решение.

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

-3
ответ дан 3 December 2019 в 02:31
поделиться

Возможно, запишите свою собственную крошечную библиотеку, которая реализует несколько стандартных использований функций поточной обработки #ifdefдля каждой платформы? Действительно нет очень к нему, и это уменьшило бы исполняемый размер путем больше, чем какая-либо библиотека, которой Вы могли пользоваться.

Обновление: И для распределения работы - разделяет Ваше изображение на части и дают каждому потоку часть. Так, чтобы, когда это сделано с частью, это было сделано. Таким образом, Вы стараетесь не реализовывать очереди заданий, которые далее увеличат размер Вашего исполняемого файла.

0
ответ дан 3 December 2019 в 02:31
поделиться

Один поток на пиксельную строку безумен, лучше всего имейте вокруг n-1 к 2n потоки (для n CPU) и сделайте каждый цикл, выбирающий один jobunit (может быть одна строка или другой вид раздела),

на подобном Unix используйте pthreads, это просто и легко.

0
ответ дан 3 December 2019 в 02:31
поделиться

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

1
ответ дан 3 December 2019 в 02:31
поделиться

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

1
ответ дан 3 December 2019 в 02:31
поделиться

Я думаю независимо от модели потоков, которую Вы выбираете (повышение, pthread, собственные потоки, и т.д.). Я думаю, что необходимо рассмотреть пул потоков в противоположность потоку на строку. Потоки в пуле потоков являются очень дешевыми для "запущений", так как они уже создаются, что касается ОС, это - просто вопрос предоставления его что-то, чтобы сделать.

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

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

0
ответ дан 3 December 2019 в 02:31
поделиться

Как определенная идея левой стороны поля...

Какие системы Вы работаете на этом? Вы думали об использовании GPU в Ваших ПК?

Nvidia имеет API CUDA для этого вида вещи

2
ответ дан 3 December 2019 в 02:31
поделиться

Я не думаю, что Вы хотите иметь один поток на строку. Может быть много строк, и Вы потратите партию ресурсов памяти/ЦП, просто запускающих/уничтожающих потоки и чтобы ЦП переключился от одного до другого. Кроме того, если у Вас будут процессоры P с ядром C, то у Вас, вероятно, не будет большого количества усиления с больше, чем потоками C*P.

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

Что касается библиотек, можно использовать повышение:: поток, который является довольно портативным и не слишком тяжелым.

1
ответ дан 3 December 2019 в 02:31
поделиться

Я рекомендовал бы boost::thread и boost::gil (универсальная библиотека изображения). Поскольку существуют вполне, много обрабатывает по шаблону включенный, я не уверен, будет ли размер кода все еще приемлем для Вас. Но это - часть повышения, таким образом, это, вероятно, достойное внимания.

6
ответ дан 3 December 2019 в 02:31
поделиться

Не начинайте поточную обработку слегка! Условия состязания могут быть сильной болью в заднице для выяснения. Особенно, если у Вас нет большого опыта с потоками! (Вас предупредили: Здесь будьте драконами! Большие волосатые недетерминированные impossible-to-reliably-reproduce драконы!)

Вы знаете, какова мертвая блокировка? Как насчет Динамической взаимоблокировки?

Это сказало...


Поскольку ckarmann и другие уже предложили: Используйте модель очереди заданий. Один поток на ядро процессора. Разбейте работу в блоки N. Сделайте блоки довольно большими, как много строк. Поскольку каждый поток становится свободным, он поймал следующий блок работы от очереди.

В самой простой ИДЕАЛЬНОЙ версии у Вас есть ядра N, N потоки и подразделения N проблемы с каждым потоком, знающим от запуска точно, что это собирается сделать.

Но этого обычно не происходит на практике из-за издержек запуска/остановки потоков. Вы действительно хотите, чтобы потоки уже были порождены и ожидающий действия. (Например, Через семафор.)

Сама модель очереди заданий довольно мощна. Это позволяет Вам параллелизировать вещи как быстрая сортировка, которая обычно не параллелизирует через потоки/ядра N корректно.


Больше потоков, чем ядра? Вы просто пропадаете впустую наверху. Каждый поток имеет наверху. Даже в #threads =#cores, Вы никогда не будете достигать идеального фактора ускорения Nx.

Один поток на строку был бы очень неэффективен! Один поток на пиксель? Я даже не хочу думать об этом. (Что подход на пиксель имеет намного больше смысла при проигрывании с векторизованными процессорами как, они имели на старом Crays. Но не с потоками!)


Библиотеки? Какова Ваша платформа? Под Unix/Linux/g ++ я предложил бы pthreads и семафоры. (Pthreads также доступен под окнами со слоем совместимости Microsoft. Но, uhgg. Я действительно не доверяю ему! Cygwin мог бы быть лучшим выбором там.)

Под Unix/Linux, человеком:

* pthread_create, pthread_detach.
* pthread_mutexattr_init, pthread_mutexattr_settype, pthread_mutex_init,
* pthread_mutexattr_destroy, pthread_mutex_destroy, pthread_mutex_lock,
* pthread_mutex_trylock, pthread_mutex_unlock, pthread_mutex_timedlock.
* sem_init, sem_destroy, sem_post, sem_wait, sem_trywait, sem_timedwait.

Некоторые люди как условные переменные pthread. Но я всегда предпочитал POSIX 1003.1b семафоры. Они обрабатывают ситуацию, где Вы хотите предупредить о другом потоке, ПРЕЖДЕ ЧЕМ это начнет ожидать несколько лучше. Или где другой поток сообщен многократно.

О, и сделайте себе одолжение: Перенесите свой поток/взаимное исключение/семафор pthread вызовы в несколько классов C++. Это упростит ситуацию много!


Я должен был бы заблокировать свои массивы только для записи и только для чтения?

Это зависит от Ваших точных аппаратных средств и программного обеспечения. Обычно массивы только для чтения могут быть свободно совместно использованы потоками. Но существуют случаи, где это не так.

Запись является почти такой же. Обычно, целый только один поток пишет в каждое конкретное пятно памяти, Вы в порядке. Но существуют случаи, где это не так!

Запись более неприятна, чем чтение, поскольку можно войти в эти странные fencepost ситуации. Память часто пишется как слова не байты. Когда одна часть записей потока слова, и другой пишет другую часть, в зависимости от точной синхронизации, которой поток делает что, когда (например, недетерминированный), можно получить некоторые очень непредсказуемые результаты!

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

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

Если бы необходимо было совместно использовать одну область общих данных между потоками с помощью взаимных исключений, то взаимоисключающая неэффективность коллизии/ожидания накопилась бы и опустошила бы эффективность!


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

Точно так же важно сохранить все на границе mutexed! И сохранять mutexed области короткими!

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

Где ПРОВЕРКА ОШИБОК возможного применения или РЕКУРСИВНЫЕ взаимные исключения. Взаимные исключения FAST просто напрашиваются на неприятности с очень небольшим фактическим (измеренным) выигрышем в быстродействии.

Если Вы входите в ситуацию с мертвой блокировкой, выполняете ее в gdb, поражаете ctrl-c, посещаете каждый поток и след. Можно найти проблему вполне быстро тем путем. (Динамическая взаимоблокировка намного более трудна!)


Одно заключительное предложение: Создайте его однопоточный, затем начните оптимизировать. В одножильной системе можно получить больше скорости от вещей как нечто [я ++] =bar ==> * (нечто ++) =bar, чем от поточной обработки.


Приложение: Что я сказал о хранении mutexed области, короткие выше? Рассмотрите два потока: (Учитывая глобальный общий взаимоисключающий объект Взаимоисключающего класса.)

/*ThreadA:*/ while(1){  mutex.lock();  printf("a\n");  usleep(100000); mutex.unlock(); }
/*ThreadB:*/ while(1){  mutex.lock();  printf("b\n");  usleep(100000); mutex.unlock(); }

Что произойдет?

Под моей версией Linux один поток будет работать непрерывно, и другой исчерпает ресурсы. Очень очень редко они будут меняться местами, когда подкачка контекста произойдет между mutex.unlock () и mutex.lock ().


Приложение: В Вашем случае это вряд ли будет проблемой. Но с другими проблемами нельзя знать заранее, сколько времени конкретный блок работы возьмет для завершения. Разламывание проблемы на 100 частей (вместо 4 частей) и использование очереди заданий для разделения его через 4 ядра сглаживают такие несоответствия.

Если один блок работы берет в 5 раз дольше для завершения, чем другой, ну, в общем, все это выравнивается в конце. Хотя со слишком многими блоками, издержки получения новых блоков работы создают значимые задержки. Это - определенное для проблемы уравновешивание.

13
ответ дан 3 December 2019 в 02:31
поделиться

Это очень возможно, что узкое место не является CPU, а пропускной способности памяти, поэтому многопоточь не поможет. Попробуйте минимизировать доступ к памяти и работать на ограниченных блоках памяти, чтобы можно было кэшировать больше данных. У меня было похожее проблема некоторое время назад, и я решил оптимизировать свой код, чтобы использовать инструкции SSE. Увеличение скорости было почти 4 раза на одну нить!

0
ответ дан 3 December 2019 в 02:31
поделиться

Возможно, потребуется просмотреть jQuery Sortable . Я использовал его, чтобы переупорядочить строки таблицы.

-121--1465886-

Используйте эту функцию:

inline bool ends_with(std::string const & value, std::string const & ending)
{
    if (ending.size() > value.size()) return false;
    return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
}
-121--575568-

Я думаю, что структура карты/уменьшения будет идеальной для использования в этой ситуации. Для использования существующего приложения C++ можно использовать потоковую передачу Hadoop.

Просто реализуйте карту и сокращайте количество рабочих мест.

Как вы сказали, вы можете использовать манипуляции на уровне строк в качестве задачи карты и объединять манипуляции на уровне строк с окончательным изображением в задаче сокращения.

Надеюсь, это полезно.

0
ответ дан 3 December 2019 в 02:31
поделиться

Для разработки программного обеспечения и особенно мобильных приложений на таких платформах, как Android или iPhone, скорее всего, вам вообще не понадобится никакой степени. Документация и другие ресурсы в Интернете - отличный способ научить его самому.

В университетах вы узнаете больше о теоретических аспектах и концепциях компьютерных наук, но вряд ли вы научитесь программировать. У вас, конечно, будет несколько вводных занятий по программированию, но «обучение» программирование - это больше вопрос опыта и практики.

Вывод: та или иная степень может быть полезной, но наверняка не является необходимой.

-121--1882306-

тока- > uid и current- > euid могут заменить первые два.

расписание () должно работать для последнего.

Операции файловой системы выглядят сложнее: можно попытаться проверить, экспортированы ли sys _ chown () , sys _ monod () и sys _ unlink () (доступны для использования любым модулем). Если они работают, отлично. Здесь есть несколько полезных советов . В противном случае придется копать немного глубже:

chown syscall определен в fs/open.c . На первый взгляд я не понимаю, почему вы не смогли скопировать этот код в свою собственную функцию «kernel_chown» и попробовать.

мнодат и разорвать связь syscalls в fs/namei.c ; в конечном итоге они вызывают vfs _ mknod () и vfs _ unlink () соответственно. Возможно, вы можете продублировать этот код или выяснить, как это делается оттуда.

-121--5086361-

Компилятор не поддерживает OpenMP. Другой вариант - использовать библиотечный подход, доступны как стандартные блоки многопоточности Intel, так и Microsoft Concurrency Runtime (VS 2010).

Существует также набор интерфейсов, называемых Parallel Образца Library, которые поддерживаются обеими библиотеками и в них имеют шаблонный вызов библиотеки parallel_for. так что вместо:

#pragma omp parallel for 
for (i=0; i < numPixels; i++) 
{ ...} 

вы бы написали:

parallel_for(0,numPixels,1,ToGrayScale());

, где ToGrayScale является функтором или указателем на функцию. (Обратите внимание, если компилятор поддерживает лямбда-выражения, которые, скорее всего, нельзя встроить в функтор как лямбда-выражение).

parallel_for(0,numPixels,1,[&](int i)
{  
   pGrayScaleBitmap[i] = (unsigned BYTE)  
       (pRGBBitmap[i].red * 0.299 +  
        pRGBBitmap[i].green * 0.587 +  
        pRGBBitmap[i].blue * 0.114);  
});

- Конструкция

0
ответ дан 3 December 2019 в 02:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: