Версия:
Аннотация
В данной заметке показано как распараллеливать методы. Показано на примере подсчета суммы массива. Используется библиотека pthread.
Предварительная версия!
Распараллеливание позволяет повысеть скорость работы программы за счет того, что код фактически работает одновременно на несколько ядрах.
В качестве примера рассмотрим метод, который суммирует элементы массива.
Исходная версия кода Рассмотрим метод вычисления суммы элементов массива. В обычной реализации это будет стандартный цикл в котором очередной элемент добавляется к итоовой переменной:
Обособление При распараллеливание каждая версия кода живет своей отдельной жизнью. Поэтому для распараллеливания код нужно привести к соответствующему виду. Для этого нужно понять какие имено переменные нужны для коректного выполнения метода. Также слудет понять, что является результатом, т.е. возвращаемом значением. В данном случае, нужен указатель на данные и их количества. Результатом работы метода является переменая отвечающая за сумму.
Проще всего начать с создания функции, которая имеет соответсвующие аргументы. И далее переписать предыдущий код следующим образом:
Структура После такого преобразования можно обособить уже сами даные в отдельную структуру:
Отмечу, что переменная i не попала в структуру так как она является локальной, т.е. она задается и используется самим методов. Она не нужна для задания работы. Также отмечу, что результат сохранен в структуре, а не возвращается.
И переписать соответственно код:
Теперь нужно научится выполнять задания почастям.
По частям Распараллеливание осуществляется за счет того, что одновременной делаются вычисления над разыми частями задания. В данном случае, над частями массива. Часть массива характеризуется началом и концом.
Для изображения такое деление могло бы выглядить как прямоугольник изображения. Такие прямоугольники накрывают все изображения без перекрытия.
Конкретно, предполагается, что массив делится на несколько частей. Вообще говоря, равных, и каждая часть вычилсяется по отдельности. Далее итоговый ответ собирается из разных частей.
В структуру добавлены дополнительные переменные для указаия конкретного подзадания, т.е. части массива. Конкретно, добавлены переменные start и end (не включительно).
Далее как и раньше, считыаем элементы массива. Например, из файла.
После считывания подготавливаем задание для каждой подчасти массива.
Упражение. Подумай почему именно такие формулы используются для вычисления start и end.
Теперь вызываем эти подзадания. Это фактически можно рассматривать как отложенный вызов.
Обобщение Исходя из неких тонкостей принято прототип функции (т.е. тип аргумента и возвращаемого значения) делать единым. Так, аргумент делается указателем на void, аналогично с возвращаемым значением. Тогда функиця do_work доделывается так:
При вызове соответственно делается:
Параллельная работа Теперь нужно “отложеный вызов” превратить в параллельный. Для этого нужно вызвать некий системынй вызов, который это обеспечит. Стандартный способ заключается применении библиотеки pthread.
Для её использования нужке объект этоё библиотеки отвечающей за параллельную работу кода “нить”: pthread_t. Этот объект нужно вставить в нашу структуру, так как она как раз у нас и отвечает за состояние некого исполнителя. Тогда структура будет такой:
Отмечу, что в начала файла следует поместить достаточное количество загаловочных файлов. Как минимум pthread.h Полный список лучше посмотреть по комманде man pthread_create, там где показан пример.
Для запуска кода в паралель используется функция pthread_create. Тогда код будет выгляеть так:
Замечу что как прототип функции do_stuff, так и переменной tmp уже какие надо.
В отличии от отложенного вызова нельзя сразу взять и собрать каждую из подсумм. Для начала нужно дождатся когда разные нити завершат работу. Для этого вызывается системынй вызов pthread_join.
Теперь можно суммировать подсуммы как и раньше: