Показаны сообщения с ярлыком тбб. Показать все сообщения
Показаны сообщения с ярлыком тбб. Показать все сообщения

19 июн. 2009 г.

Пример функции parallel_reduce

В предыдущей статье об Intel Threading Building Blocks рассказывалось о преимуществах этой библиотеки, а также был рассмотрен пример алгоритма parallel_for. Рассмотрим пример использования алгоритма parallel_reduce, который отличается от функции parallel_for тем, что позволяет объединить частичные результаты, полученные в парралельных потоках.

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

#include <stdio.h>

#include <tbb/blocked_range.h>

#include <tbb/parallel_reduce.h>

#include <tbb/task_scheduler_init.h>

* This source code was highlighted with Source Code Highlighter.

Здесь stdio.h используется для включения функции printf (вывод на экран), blocked_range.h для использования класса blocked_range (блочный диапазон), parallel_reduce.h для включения соответствующего алгоритма, а task_scheduler_inti.h — для включения планировщика задач.

Как было сказано ранее, стандартные алгоритмы Intel TBB — parallel_for, parallel_reduce — используют концепцию класса-задачи. В примере ниже показан подобный класс для решения задачи нахождения значения константы Пи (пример навеян конкурсом Интела, а также самостоятельной работой моего студента). Суть нахождения числа заключается в вычислении площади криволинейной трапеции, которая примерно описана большим количеством прямоугольников. Чем больше прямоугольников, тем точнее значение, но тем и больше времени требуется для вычисления. Иллюстрацию к этой задаче можно посмотреть на сайте «Вольфрам-Альфа».

// Класс-задача, отвечает за подсчет значения пи на заданном диапазаоне


class PiCalculation {

private:   

// Количество шагов в интервале, влияет на точность   

long num_steps;   // Ширина шага   double step; public:   // Частичное значение пи   double pi;   // Вычислить частичное значение пи на заданном диапазоне   void operator () (const tbb::blocked_range<long> &r)   {     double sum = 0.0;     long end = r.end();     for (int i = r.begin(); i != end; i++)     {       double x = (i + 0.5) * step;       sum += 4.0/(1.0 + x * x);     }     pi += sum * step;   }   // Объеденить частичные результаты   void join(PiCalculation &p)   {     pi += p.pi;   }   // Разделяющий конструктор   PiCalculation(PiCalculation &p, tbb::split)   {     pi = 0.0;     num_steps = p.num_steps;     step = p.step;   }      // Конструктор   PiCalculation(long steps)   {     pi = 0.0;     num_steps = steps;     step = 1./(double)num_steps;   } };
* This source code was highlighted with Source Code Highlighter.

Важными в этом классе есть следующие два метода: operator () и join.

Метод void operator () (const blocked_range &r) вычисляет частичный результат в интервале [r.begin, r.end). Библиотека Intel TBB и класс blocked_range заботятся о том, чтобы рекурсивно разбить исходное пространство итераций и «скармливать» небольшими порциями методу operator (). Результат накапливается в переменной pi, которая частная для потока. Дается гарантия, что operator () для одного класса будет вызван только из одного потока, поэтому ошибки типа «гонки за данными» (data races, race conditions) исключены.

Метод void join (PiCalculation &p) суммирует частные результаты различных потоков. Здесь проявляется важное отличие библиотеки Intel TBB от библиотек OpenMP и MPI, в которых количество операций для объединения частичных результатов (reduction, редуцирование) ограничено. Intel TBB позволяет реализовать произвольные функции объединения результатов в теле метода join.

Рассмотрим запуск алгоритма parallel_reduce.

int main() {   // Инициализация библиотеки Intel TBB   tbb::task_scheduler_init init;   // Количество итераций   const long steps = 100000000;   // Создание объекта-задачи по вычислению пи   // Передается параметр: количество итераций   PiCalculation pi(steps);   // Запуск алгоритма parallel_reduce над диапазоном [0, steps)   tbb::parallel_reduce(tbb::blocked_range<long>(0, steps, 1000000), pi);   printf ("Pi is %3.20f\n", pi.pi);   return 0; } * This source code was highlighted with Source Code Highlighter.

Для этого необходимо выполнить следующие шаги: создать объект планировщика задач Intel TBB, создать объект задачи PiCalculation, и вызвать функцию parallel_reduce. Здесь функция принимает два параметра. Первый — это класс диапазона. В нашем случае мы указывает количество итераций [0, steps), т. е. при вычислении интеграла от 0 до 1 будет использовано steps = 100 000 000 шагов. Второй параметр — это ссылка на объект задачи, в котором после возвращения из функции parallel_reduce будет содержаться значение пи.

29 мая 2009 г.

Шлакоблоки параллельного программирования

Существует несколько способов, как добиться от программистов большой скорости решения поставленных задач с минимальным количеством ошибок. Первый способ — использование языков высокого уровня, например, С++. Объектно-ориентированное программирование позволяет создать в коде сущности различной природы, а также определять операции над ними. В результате мы получаем в распоряжение набор каких-либо объектов, которые соответствуют объектам из предметной области решаемой задачи, с высокоуровневыми свойствами и методами. Детали реализации скрываются за этими высокоуровневыми методами, что позволяет программисту сосредоточиться на решении задачи. Второй способ — использование современных инструментальных средств: компиляторов, генераторов тестов, формальных верификаторов, профайлеров. Компиляторы используют внутренние оптимизации для получения лучших временных характеристик и минимальных затрат памяти. Примером таких оптимизаций может служить автоматическая конвейеризация, развертки (свёртки) или распараллеливание циклов, при котором получается более быстрая реализация программы. В этом случае решением рутинных задач программирования занимается компилятор, который, как известно, работает намного быстрее и ошибается реже, чем программист. Третий способ — использование методического обеспечения. Разработано множество методов проектирования и т. н. паттернов — подходов к решению той или иной задачи в определенном контексте. Издано множество книг и пособий, посвященных как программированию самому по себе, решению абстрактных задач, а также по применению в конкретных задачах народного хозяйства. Четвертый способ — использование библиотек, которые содержат готовые протестированные решения: алгоритмы и структуры данных. Используя библиотечные компоненты, во-первых, сокращается время на разработку, а, во-вторых, сокращается время на тестирование проекта, потому что библиотечные компоненты протестированы заранее и неоднократно были внедрены в промышленные проектах. Таким образом, объем библиотечного кода может существенно превышать объем кода, написанного программистом. Сделаем краткий обзор технологий, которые повышают производительность программистов, разрабатывающих параллельные приложения. Многие годы самым доступным способом многопоточного программирования было использование библиотеки Windows API или POSIX Threads. Программисту приходилось решать поставленные задачи на очень низком уровне. Например, программисту необходимо:
  • самостоятельно создавать и удалять потоки;
  • определять те функции, которые должны выполняться в потоке;
  • передавать в поток нужные параметры;
  • использовать различные функции для синхронизации потоков;
  • обеспечить равномерную загрузку потоков вычислениями;
  • позаботиться о масштабируемости полученного решения.
Очевидно, что недостаток такого подхода заключается в том, что преобразование последовательной программы в параллельную может занять много времени. Также полученное решение будет подвержено множеству ошибок. Часть этих проблем была успешно решена в библиотеке OpenMP. Эта библиотека реализована в виде набора функций и директив — специальных расширений к компилятору. Программист в требуемом месте применяет ту или иную директиву, а компилятор в указанном месте подставляет вызовы системных функций. Например, распараллеливание цикла осуществляется единственной директивой компилятору. При этом компилятор позаботится о создании и синхронизации потоков, разделении итераций между потоками, а также хорошим балансом загрузки. Такой подход позволяет решить ограниченный класс задач практически без ошибок и в краткий срок. Но библиотека OpenMP имеет ряд ограничений и недостатков. Укажем лишь некоторые из них.
  1. Циклы с неизвестным количеством итераций не могут быть распараллелены.
  2. Существенные ограничения на параметры цикла.
  3. Ограниченные возможности по распределению работы между потоками.
  4. Операция reduction ограничена восемью элементарными операциями.
  5. Отсутствие более сложных шаблонов, чем параллельный цикл или параллельная секция.
Intel Threading Building Blocks (далее ТББ) — новая библиотека для многопоточного программирования, разработанная фирмой Интел. Библиотека имеет ряд функций и классов для решения распространенных задач параллельного программирования:
  • функция parallel_for для организации параллельного цикла;
  • функция parallel_reduce для параллельного цикла с последующей комбинацией частичных результатов;
  • класс parallel_while для создания параллельного цикла с неизвестным количеством итераций;
  • класс pipeline для организации конвейерных вычислений;
  • контейнеры с возможностью параллельного доступа: concurrent_vector, concurrent_queue, concurrent_hash_map.
В ТББ введена концепция объекта-задачи — класс С++, в котором определен оператор (), который выполняет поставленную задачу (см. листинг ниже). В зависимости от алгоритма, в котором используется объект-задача, этот оператор, например, может принимать в качестве параметра диапазон итераций (parallel_for, parallel_reduce) или очередной элемент для обработки (parallel_while, pipeline).
// Класс-задача
class Body
{
public:
    // Оператор-обработчик
    void operator() ()
    {
        // Здесь расположены вычисления
    }
};


* This source code was highlighted with Source Code Highlighter.
Здесь видно отличие от программирования обычных потоков: программист создает задачи, а не потоки. Библиотека ТББ при инициализации создает необходимое количество потоков, а встроенный планировщик назначает задачи на эти потоки во время работы программы. Функции-шаблоны parallel_for и parallel_reduce работают с диапазонами (пространствами итераций). Библиотека ТББ предоставляет для этого два класса: blocked_range и bloced_range2d, одномерное и многомерное пространство соответственно. ТББ рекурсивно делит исходный диапазон на множество блоков, которые передаются в качестве параметров для оператора-обработчика. Таким образом, каждый объект-задача делает вычисления над собственной порцией итераций. Приведем пример использования одномерного диапазона.
blocked_range<int>(begin, end, grainsize)
Здесь параметр шаблона — это тип элементов диапазона, begin — начальная точка, end — конечная точка. Пара begin и end описывает полуоткрытый интервал [begin, end), например, цикл for (int i = 2; i < 5; i++) соответствует интервалу [2; 5) и включает в себя итерации 2, 3, 4. Параметр grainsize определяет размер неделимого блока итераций. В том случае, если на очередном этапе разделения исходного диапазона встретится блок, меньший, чем grainsize, то он будет считаться неделимым. На рисунке ниже показан пример рекурсивного разделения диапазона blocked_range(0, 10, 3).
В завершении статьи приведем пример распараллеливания цикла for.
#include "tbb/blocked_range.h"
#include "tbb/parallel_for.h"
#include "tbb/task_scheduler_init.h"

using namespace tbb;

///////////////////////////////////////////////////////////////////////////////

// Класс-задача
class MyTask
{
public:
    // Метод-обработчик выполняет функцию Calculate для каждого элемента
    // блока итераций.
    void operator() (const blocked_range<int>& r) const
    {
        for (int i = r.begin(); i != r.end(); i++)
            Calculate(i);
    }
};

///////////////////////////////////////////////////////////////////////////////

int main()
{
    // Инициализация библиотеки ТББ
    task_scheduler_init init;

    // Запуск шаблона parallel_for, который принимает два параметра:
    // * объект диапазона итераций [0, 1000000)
    // * объект-задачу
    parallel_for(blocked_range<int>(0, 1000000, 10000), MyTask);

    return 0;
}

///////////////////////////////////////////////////////////////////////////////


* This source code was highlighted with Source Code Highlighter.

8 мая 2009 г.

Завел статью по ТББ на Википедии

Создал статью о Intel Threading Building Blocks на Википедии: ТББ. Ещё нужно дописать базовых вещей, историю и пример использования. У кого что есть сказать по теме — присоединяйтесь! Обычно я пишу статью в личной песочнице, а потом публикую. Но вчера что-то где-то ошибся, и статья попала в общее пространство статей, где её сразу же выставили на удаление, из-за неэнциклопедичности (там было два предложения). Сейчас в панике дописал ещё пару абзацев. Скоро напишу здесь несколько статей по ТББ и по использованию. P. S. А ещё я давно завел статьи о SystemC и о Сергее Щелкановцеве.

Темы

2012 (2) амазон (1) анпакинг (1) артемий лебедев (4) атн (1) аудио (1) аэропорт (1) безопасность (3) бизнес (1) билайн (1) блог (2) будущее (2) видео (11) википедия (5) вымысел (16) гагарин (1) герман (1) гитхаб (1) гугл (3) дед мороз (1) декабрь (1) демотиватор (2) дети (2) дизайн (13) диссертация (2) документация (1) друзья (5) евпатория (1) евро-2012 (1) жадность (1) заяц (1) идея (1) имейл (1) инстаграм (1) интервью (5) интересное (20) интерфейс (13) история (7) как_выжить (4) календарь (1) капитализм (1) картина (1) кмб (6) книга (6) коллекция (4) компилятор (2) конкурс (5) космос (1) лаборатория (1) либералы (1) лингво (1) лузер (6) макаренко (2) макдональдс (2) математика (1) медиапорт (1) ментор (1) металлика (1) металлист (2) метро (7) микрософт (6) миргород (1) москва (2) музыка (3) наркомания (1) новости (17) образование (3) оптимизация (5) основы (14) открытки (3) ошибка (11) памятник (1) патриотизм (3) плагиат (1) плата (1) погода (3) поиск (1) политика (2) полтава (2) праздник (1) программирование (15) прошлое (2) путешествия (8) рейтинг (1) рендер (1) рисунок (2) русские (1) русский язык (1) сайт (4) санкт-петербург (1) сапр (7) сеть (1) си++ (1) синтез (1) системси (1) скриншот (40) социализм (1) соцопрос (3) спектрум (2) спорт (2) срач (2) статистика (1) такси (1) тбб (3) твитер (9) тимошенко (1) украина (5) униан (1) фан (30) фокус (1) фото (39) фотошоп (1) фурсенко (1) футбол (2) хабр (1) харьков (21) хнурэ (19) хобби (4) цитата (2) чехия (1) школа (1) эпл (1) эхостар (1) юмор (1) яндекс (1) clang (2) doxygen (1) english (3) ios (1) llvm (1) msdn (1) outlook (1) PHP (1) stackoverflow (1)

Поиск

Читатели