Презентация посвящена вопросам использования параллельных алгоритмов для создания современных эффективных программных решений. Актуальность данной тематики обусловлена снижением темпов роста тактовой частоты микропроцессоров и возрастанием внимания к использованию всех возможностей многоядерных и многопроцессорных систем. В работе рассмотрен ряд базовых параллельных алгоритмов, таких как умножение матриц, параллельная сортировка Бэтчера, метод Гаусса решения систем линейных алгебраических уравнений и так далее. Приведена реализация этих алгоритмов c использованием языка программирования Си++.
Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный...Ontico
Что нужно хранить для того, чтобы была возможность ответить на этот вопрос?
Для точного ответа нужно через равные интервалы времени сохранять множество посетителей сайта (пусть это для простоты будут IP-адреса), которых мы за прошедший интервал увидели. Понятное дело, что такой объём информации хранить нереально, а даже, если получится, придётся объединять большое количество множеств и считать элементы в том множестве, которое получилось в итоге. Это очень долго. Не спасает ситуацию даже переход от точных алгоритмов к приблизительным: гарантировать точность либо не получится, либо придётся использовать объём памяти и вычислительные ресурсы, сопоставимые с точным алгоритмом.
В 80-х годах появились первые вероятностные алгоритмы для приблизительной оценки количества элементов в множестве. При большом количестве уникальных элементов эти алгоритмы дают приблизительную оценку, которая отличается от истинного значения в (1±e), e<1>0.5. То есть они могут вернуть оценку, которая сильно отличается от истинного значения с некоторой вероятностью (1-p). Чем больше требуется точность, и чем меньше нужна вероятность ошибки, тем больше ресурсов требуют алгоритмы. Сохраняя внутреннее состояние одного из таких алгоритмов через равные промежутки времени в базе данных, мы можем оценить приблизительное количество уникальных посетителей не только за произвольный интервал времени, но и за произвольное объединение любых интервалов времени, например, мы можем посчитать общее количество уникальных IP, которых мы наблюдали в промежутке времени с 17:00 до 18:00 в течение последней недели.
В 2000-ные в научном сообществе велась активная работа по достижению теоретически оптимальных характеристик (т.е. потребление памяти, сложность добавления нового элемента, сложность запроса) вероятностных приблизительных алгоритмов для оценки кардинальности (количества элементов в множестве), разрабатывался необходимый инструментарий.
Первый такой алгоритм был предложен в 2010 году. О нём-то мы и поговорим.
Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...Alexey Paznikov
ЛЕКЦИЯ 2. Коллективные операции в стандарте MPI
Курс "Параллельные вычислительные технологии" (ПВТ), осень 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
http://cpct.sibsutis.ru/~apaznikov/teaching
ЛЕКЦИЯ 1. Актуальность параллельных вычислений. Анализ параллельных алгоритмов. Многоядерные вычислительные систем с общей памятью
Курс "Параллельные вычислительные технологии" (ПВТ), весна 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
Доклад Кулагина И.И., Пазникова А.А., Курносова М.Г. "Оптимизация информационных обменов в параллельных PGAS-программах" на 3-й Всероссийской научно-технической конференции «Суперкомпьютерные технологии» (СКТ-2014)
29 сентября – 4 октября 2014 г., с. Дивноморское
ЛЕКЦИЯ 6. Параллельная сортировка. Алгоритмы комбинаторного поиска. Параллельный ввод-вывод в MPI
Курс "Параллельные вычислительные технологии" (ПВТ), осень 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
http://cpct.sibsutis.ru/~apaznikov/teaching
ПВТ - весна 2015 - Лекция 2. POSIX Threads. Основные понятия многопоточного п...Alexey Paznikov
ЛЕКЦИЯ 2. POSIX Threads. Жизненный цикл потоков. Планирование. Синхронизация
Курс "Параллельные вычислительные технологии" (ПВТ), весна 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный...Ontico
Что нужно хранить для того, чтобы была возможность ответить на этот вопрос?
Для точного ответа нужно через равные интервалы времени сохранять множество посетителей сайта (пусть это для простоты будут IP-адреса), которых мы за прошедший интервал увидели. Понятное дело, что такой объём информации хранить нереально, а даже, если получится, придётся объединять большое количество множеств и считать элементы в том множестве, которое получилось в итоге. Это очень долго. Не спасает ситуацию даже переход от точных алгоритмов к приблизительным: гарантировать точность либо не получится, либо придётся использовать объём памяти и вычислительные ресурсы, сопоставимые с точным алгоритмом.
В 80-х годах появились первые вероятностные алгоритмы для приблизительной оценки количества элементов в множестве. При большом количестве уникальных элементов эти алгоритмы дают приблизительную оценку, которая отличается от истинного значения в (1±e), e<1>0.5. То есть они могут вернуть оценку, которая сильно отличается от истинного значения с некоторой вероятностью (1-p). Чем больше требуется точность, и чем меньше нужна вероятность ошибки, тем больше ресурсов требуют алгоритмы. Сохраняя внутреннее состояние одного из таких алгоритмов через равные промежутки времени в базе данных, мы можем оценить приблизительное количество уникальных посетителей не только за произвольный интервал времени, но и за произвольное объединение любых интервалов времени, например, мы можем посчитать общее количество уникальных IP, которых мы наблюдали в промежутке времени с 17:00 до 18:00 в течение последней недели.
В 2000-ные в научном сообществе велась активная работа по достижению теоретически оптимальных характеристик (т.е. потребление памяти, сложность добавления нового элемента, сложность запроса) вероятностных приблизительных алгоритмов для оценки кардинальности (количества элементов в множестве), разрабатывался необходимый инструментарий.
Первый такой алгоритм был предложен в 2010 году. О нём-то мы и поговорим.
Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...Alexey Paznikov
ЛЕКЦИЯ 2. Коллективные операции в стандарте MPI
Курс "Параллельные вычислительные технологии" (ПВТ), осень 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
http://cpct.sibsutis.ru/~apaznikov/teaching
ЛЕКЦИЯ 1. Актуальность параллельных вычислений. Анализ параллельных алгоритмов. Многоядерные вычислительные систем с общей памятью
Курс "Параллельные вычислительные технологии" (ПВТ), весна 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
Доклад Кулагина И.И., Пазникова А.А., Курносова М.Г. "Оптимизация информационных обменов в параллельных PGAS-программах" на 3-й Всероссийской научно-технической конференции «Суперкомпьютерные технологии» (СКТ-2014)
29 сентября – 4 октября 2014 г., с. Дивноморское
ЛЕКЦИЯ 6. Параллельная сортировка. Алгоритмы комбинаторного поиска. Параллельный ввод-вывод в MPI
Курс "Параллельные вычислительные технологии" (ПВТ), осень 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
http://cpct.sibsutis.ru/~apaznikov/teaching
ПВТ - весна 2015 - Лекция 2. POSIX Threads. Основные понятия многопоточного п...Alexey Paznikov
ЛЕКЦИЯ 2. POSIX Threads. Жизненный цикл потоков. Планирование. Синхронизация
Курс "Параллельные вычислительные технологии" (ПВТ), весна 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
Лекция 4. Производные типы данных в стандарте MPIAlexey Paznikov
ЛЕКЦИЯ 4. Производные типы данных в стандарте MPI
Курс "Параллельные вычислительные технологии" (ПВТ), осень 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
http://cpct.sibsutis.ru/~apaznikov/teaching
Лекция 3. Виртуальные топологии в MPI. Параллельные алгоритмы в стандарте MPI...Alexey Paznikov
ЛЕКЦИЯ 3. Виртуальные топологии в MPI. Параллельные алгоритмы в стандарте MPI умножения матрицы на вектор, метода Монте-Карло, решение линейных алгебраических уравнений (СЛАУ) методами Гаусса и сопряжённых градиентов
Курс "Параллельные вычислительные технологии" (ПВТ), осень 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
http://cpct.sibsutis.ru/~apaznikov/teaching
ЛЕКЦИЯ 4. Шаблоны многопоточного программирования
Курс "Параллельные вычислительные технологии" (ПВТ), весна 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
ЛЕКЦИЯ 8. Многопоточное программирование без использования блокировок. Модель потребитель-производитель. Потокобезопасный стек. Проблема ABA. Указатели опасности.
Курс "Параллельные вычислительные технологии" (ПВТ), весна 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
ЛЕКЦИЯ 3. Реентерабельность. Сигналы. Локальные данные потоков. Принудительное завершение потоков
Курс "Параллельные вычислительные технологии" (ПВТ), весна 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
Иван Пузыревский — Введение в асинхронное программированиеYandex
Доклад посвящен основам асинхронного программирования. Мы кратко обсудим историю вопроса: что такое асинхронность, где, почему и зачем она используется. Затем рассмотрим наиболее частые способы построения асинхронных интерфейсов: основанные на callback'ах и на future/promise. В ходе доклада выделим основные используемые концепции, посмотрим на их реализацию и примеры использования. А в конце поговорим о сложностях, которые часто встречаются в асинхронном программировании.
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...Yandex
Флеш-накопители используются в самых разных устройствах, от мобильных телефонов до компьютеров и серверов. Для каждой модели накопителя нужна прошивка с определённым набором параметров, которые могут отличаться в зависимости от ситуации. В докладе будет описан универсальный фреймфорк на С++, который предоставляет разработчикам симуляторов простой, прозрачный и быстрый доступ к любому параметру. Тестировщикам же он позволяет управлять конфигурациями при помощи стандартных инструментов редактирования и слияния.
Лекция 4. Производные типы данных в стандарте MPIAlexey Paznikov
ЛЕКЦИЯ 4. Производные типы данных в стандарте MPI
Курс "Параллельные вычислительные технологии" (ПВТ), осень 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
http://cpct.sibsutis.ru/~apaznikov/teaching
Лекция 3. Виртуальные топологии в MPI. Параллельные алгоритмы в стандарте MPI...Alexey Paznikov
ЛЕКЦИЯ 3. Виртуальные топологии в MPI. Параллельные алгоритмы в стандарте MPI умножения матрицы на вектор, метода Монте-Карло, решение линейных алгебраических уравнений (СЛАУ) методами Гаусса и сопряжённых градиентов
Курс "Параллельные вычислительные технологии" (ПВТ), осень 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
http://cpct.sibsutis.ru/~apaznikov/teaching
ЛЕКЦИЯ 4. Шаблоны многопоточного программирования
Курс "Параллельные вычислительные технологии" (ПВТ), весна 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
ЛЕКЦИЯ 8. Многопоточное программирование без использования блокировок. Модель потребитель-производитель. Потокобезопасный стек. Проблема ABA. Указатели опасности.
Курс "Параллельные вычислительные технологии" (ПВТ), весна 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
ЛЕКЦИЯ 3. Реентерабельность. Сигналы. Локальные данные потоков. Принудительное завершение потоков
Курс "Параллельные вычислительные технологии" (ПВТ), весна 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
Иван Пузыревский — Введение в асинхронное программированиеYandex
Доклад посвящен основам асинхронного программирования. Мы кратко обсудим историю вопроса: что такое асинхронность, где, почему и зачем она используется. Затем рассмотрим наиболее частые способы построения асинхронных интерфейсов: основанные на callback'ах и на future/promise. В ходе доклада выделим основные используемые концепции, посмотрим на их реализацию и примеры использования. А в конце поговорим о сложностях, которые часто встречаются в асинхронном программировании.
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...Yandex
Флеш-накопители используются в самых разных устройствах, от мобильных телефонов до компьютеров и серверов. Для каждой модели накопителя нужна прошивка с определённым набором параметров, которые могут отличаться в зависимости от ситуации. В докладе будет описан универсальный фреймфорк на С++, который предоставляет разработчикам симуляторов простой, прозрачный и быстрый доступ к любому параметру. Тестировщикам же он позволяет управлять конфигурациями при помощи стандартных инструментов редактирования и слияния.
Казалось, закончились долгие обсуждения в форумах, как измерить время работы алгоритма, какие функции использовать, какую точность ожидать. Жаль, но опять придется вернуться к этому вопросу. На повестке дня вопрос – как лучше измерить скорость работы параллельного алгоритма.
Оптимизация трассирования с использованием Expression templatesPlatonov Sergey
В докладе будет рассказано о тех фундаментальных причинах, приводящих к неоптимальному коду в продукте, будет предложен подход, лишённый найденных недостатков.
Докладываемый подход опирается на технологию Expression Templates, которая позволяет уменьшить количество действий и объём ресурсов, которые требуются для выполнения неких промежуточных действий в процессе формирования каждой записи в журнал. Эта технология используется для уменьшения количества промежуточных операций при вычислении сложных математических выражений. Новизна докладываемого подхода в том, что тот же самый принцип, на котором основана технология Expression Templates можно применить для того, чтобы целенаправленно исключить те промежуточные действия, которые в конечном итоге приводят к неоптимальному коду.
Завершается доклад обсуждением полученного эффекта, путей возможного дальнейшего развития и возможностей применения этой же технологии в других задачах.
В третьей главе рассматриваются базовые свойства акторов, описанные в PhD диссертации Gul Agha: каждый актор имеет адрес, большой почтовый ящик, куда доставляются сообщения, адресованные актору и поведение. В ответ на входящее сообщение актор может отправить конечный набор сообщений другим акторам и/или создать конечное число новых акторов и/или поменять свое поведение для обработки следующего сообщения.
В рамках данного курса будет разработана библиотека для разработки параллельных приложений на платформе .NET, построенная по модели акторов.
Исходные коды библиотеки будут выкладываться на GitHub: https://github.com/hwdtech/HWdTech.DS
Код библиотеки будет разработан с использованием следующих принципов, приемов и методик:
S.O.L.I.D. - принципы
Unit-tests
Mock
IoC контейнеры
Для удобства слушателей курса краткий обзор данных практик приведен в Главе 4.
разработка серверов и серверных приложений лекция №3etyumentcev
В третьей главе рассматриваются базовые свойства акторов, описанные в PhD диссертации Gul Agha: каждый актор имеет адрес, большой почтовый ящик, куда доставляются сообщения, адресованные актору и поведение. В ответ на входящее сообщение актор может отправить конечный набор сообщений другим акторам и/или создать конечное число новых акторов и/или поменять свое поведение для обработки следующего сообщения.
В рамках данного курса будет разработана библиотека для разработки параллельных приложений на платформе .NET, построенная по модели акторов.
Исходные коды библиотеки будут выкладываться на GitHub: https://github.com/hwdtech/HWdTech.DS
Код библиотеки будет разработан с использованием следующих принципов, приемов и методик:
S.O.L.I.D. - принципы
Unit-tests
Mock
IoC контейнеры
Для удобства слушателей курса краткий обзор данных практик приведен в Главе 4.
2. Аннотация
Статья посвящена вопросам использования параллельных алгоритмов для создания современных
эффективных программных решений. Актуальность данной тематики обусловлена снижением темпов роста
тактовой частоты микропроцессоров и возрастанием внимания к использованию всех возможностей
многоядерных и многопроцессорных систем. В работе рассмотрен ряд базовых параллельных алгоритмов,
таких как умножение матриц, параллельная сортировка Бэтчера, метод Гаусса решения систем линейных
алгебраических уравнений и так далее. Приведена реализация этих алгоритмов c использованием языка
программирования Си++.
3. Введение
В ближайшее время под эффективным использованием аппаратных средств компьютера будут пониматься
применение параллельных алгоритмов. Это связано с замедлением темпов роста тактовой частоты
микропроцессоров и быстрым распространением многоядерных микропроцессоров.
Создание эффективных программных решений для параллельных систем складывается из трех основных
компонентов: параллельных алгоритмов, средств реализации параллельности и систем отладки.
Под средствами реализации параллельности понимаются языки программирования или библиотеки,
обеспечивающие инфраструктуру параллельных программ. Таких система достаточно много. К ним можно
отнести: Occam, MPI, HPF, OpenMP, DVM, OpenTS, Boost.Thread, Posix Threads. Сюда также можно отнести
библиотеку Integrated Performance Primitives компании Intel.
Поскольку отладка параллельной программы является процессом более трудоемким, чем отладка
последовательной программы, то системы отладки и профилирования являются важнейшей частью в процессе
разработки таких систем. В области отладчиков хочется обратить внимание на системы TotalView и PGDBG.
Среди средств профилирования можно назвать такие инструменты как Nupshot, Pablo, Vampir. Существуют
системы статической верификации, например VivaMP. Последней инструмент, на который хочется обратить
особое внимание, является средства анализа многопоточности Threading Analysis Tools.
4. Но самый важный компонент, без которого все другие средства не смогут сделать программу параллельной,
это параллельный алгоритм. Именно этому компоненту и будет посвящена эта статья.
В статье будут рассмотрены несколько базовых параллельных алгоритмов, имеющих практическое значение
во многих областях, в том числе в экономике, в численном моделировании и в задачах реального времени.
Для некоторых алгоритмов приведены оценки времени выполнения последовательной и параллельной
версий алгоритма и выведены коэффициенты ускорения. Приведен пример реализации описанных
алгоритмов c использованием языка программирования Си++ в среде Windows.
5. 1. Параллельная сортировка Бэтчера
Алгоритм сортировки Бэтчера не является наиболее эффективным алгоритмом сортировки, однако он
обладает одним важным компенсирующим качеством: все сравнения и/или обмены, определяемые данной
итерацией алгоритма можно выполнять одновременно. С такими параллельными операциями сортировка
осуществляется за . Например, 1024 элемента можно рассортировать методом Бэтчера
всего за 55 параллельных шагов. Схема сортировки Бэтчера несколько напоминает сортировку Шелла, но
сравнения выполняются по-новому, а потому цепочки операций обмена записей не возникает. Поскольку в
алгоритме Бэтчера, по существу, происходит слияние пар рассортированных подпоследовательностей, его
можно назвать обменной сортировкой со слиянием.
Алгоритм Бэтчера (обменная сортировка со слиянием). Записи перекомпоновываются в пределах того
же пространства в памяти. После завершения сортировки их ключи будут упорядочены: .
Предполагается, что .
1)[начальная установка .] Установить , где — наименьшее целое число, такое, что .
(Шаги 2-5 будут выполняться с .)
2)[начальная установка .] Установить .
3)[цикл по .] Для всех , таких, что и , выполнять шаг 4.
6. Затем перейти к шагу 5. (Здесь через обозначена операция "поразрядное логическое И" над
представлениями целых чисел и ; все биты результата равны 0, кроме тех битов, для которых в
соответствующих разрядах и находятся 1. Так . К этому моменту —
нечётное кратное (т.е. частное от деления на нечётно), а — степень двойки, так что .
Отсюда следует, что шаг 4 можно выполнять при всех нужных значениях в любом порядке или даже
одновременно.)
4)[Сравнение/обмен .] Если , поменять местами записи .
5)[Цикл по .] Если , установить и возвратиться к шагу 3.
6)[Цикл по ] (К этому моменту перестановка будет -упорядочена.) Установить .
Если , возвратиться к шагу 2.
7. ////////////////////////////////////////
// Параллельная сортировка Бэтчера
#include <stdio.h>
#include <stdlib.h>
#define N 16
int Arr[N];
void FillArray()
{
for (unsigned i = 0; i < N; i++)
Arr[i] = rand() % 10;
}
void PrintArray()
{
for (unsigned i = 0; i < N; i++)
printf("%d ", Arr[i]);
printf("n");
}
void BatcherSort()
{
unsigned p = N;
while (p > 0)
{
unsigned q = N, r = 0, d = p;
bool b;
do
{
unsigned nTo = N - d;
for (unsigned i = 0; i < nTo; i++)
if ((i & p) == r)
{
if (Arr[i] > Arr[i + d])
{
int temp = Arr[i];
8. Arr[i] = Arr[i + d];
Arr[i + d] = temp;
}
}
b = q != p;
if (b)
{
d = q - p;
q >>= 1;
r = p;
}
} while (b);
p >>= 1;
}
}
int main(int argc, char* argv[])
{
FillArray();
PrintArray();
BatcherSort();
PrintArray();
return 0;
}
9. 2. Вычисление корня алгебраического или трансцендентного уравнения
Пусть дано уравнение . Требуется на отрезке найти корень при условии . Для
построения алгоритма ветви используется метод хорд, заключающийся в следующем (рисунок N1).
Кривая заменяется хордой , определяется
Рисунок 1. Метод хорд.
точка , после чего проводится хорда определяется и т. д., пока .
Для реализации задачи на процессоров, т.е. для построения параллельного алгоритма из ветвей,
отрезок разбивается на подотрезков на границах которых вычисляется . Это определяет
подотрезок длиной , содержащий корень . Точки и — соседние, в них значения функции
имеют разные знаки (рисунок N1).
10. После отрезка рассматривается отрезок , где
(1)
Отрезок разбивается на частей, повторяется описанная процедура, получается отрезок и т. д.,
пока длина отрезка не станет меньше заданного значения. Параллельный счет оправдан, когда объём
вычислений значения намного превосходит объём вычислений границ отрезка по (1).
Аналогичный результат получается и при использовании метода Ньютона.
////////////////////////////////////////
// Параллельное вычисление корня уравнения
#include <windows.h>
#include <process.h>
#include <stdio.h>
#include <math.h>
#define NumberOfProcessors 3
float Func(float arg)
{
return arg * (arg - 5) + 6;
}
template <typename t> inline int sgn(t arg)
{
return arg < 0 ? -1 : (arg > 0 ? 1 : 0);
}
float x1 = 2.5;
float x2 = 10;
float e = 1;
12. FALSE, NULL);
}
for (i = 0; i < NumberOfProcessors; i++)
hThreads[i] =
(HANDLE)_beginthreadex(NULL, 0, ThreadFunction,
(void *)i, 0, &tid);
for (;;)
{
WaitForMultipleObjects(NumberOfProcessors,
hEventFinish,
TRUE, INFINITE);
int Sign = sgn(Values[0]);
if (Sign == 0)
{
Result = x1;
Action = Stop;
}
if (Action != Stop)
for (i = 1; i < NumberOfProcessors; i++)
{
int NewSign = sgn(Values[i]);
if (NewSign == 0)
{
Result = x1 + i * (x2 - x1) /
(float)(NumberOfProcessors - 1);
Action = Stop;
break;
}
if (NewSign != Sign)
{
float a = x1 + (i - 1) * (x2 - x1) /
(float)(NumberOfProcessors - 1);
float b = x1 + i * (x2 - x1) /
13. (float)(NumberOfProcessors - 1);
x1 = a + (Values[i - 1] * (b - a)) /
(Values[i] - Values[i - 1]);
x2 = b - Values[i] / M;
e = b - a;
break;
}
}
if (e < EPSILON)
{
Result = (x2 + x1) / 2;
Action = Stop;
}
for (i = 0; i < NumberOfProcessors; i++)
SetEvent(hEventStart[i]);
if (Action == Stop)
break;
}
printf("%7.4f", Result);
for (i = 0; i < NumberOfProcessors; i++)
{
CloseHandle(hThreads[i]);
CloseHandle(hEventStart[i]);
CloseHandle(hEventFinish[i]);
}
return 0;
}
14. 3. Решение системы линейных алгебраических уравнений методом простой
итерации
Система уравнений размерности записывается в виде , где — матрицы;
и — векторы; — единичная матрица.
Последовательные приближения вычисляются по формуле , начиная с некоторого исходного
приближения . Процесс завершается, если . Последовательность в методе простой
итерации сходится, если для матрицы выполняется одно из неравенств
Применим к матрице и векторам и распределение горизонтальными полосами. Для нахождения
в соответствующей ветви необходимы строка матрицы , вектор и значение . Поэтому можно
обеспечить каждую ветвь всеми необходимыми данными для автономной работы. Отсюда
15. где — число строк матрицы и компонентов векторов и , обрабатываемых отдельной ветвью, —
время обмена данными, — время выполнения сложения, — время выполнения умножения.
#include <windows.h>
#include <process.h>
#include <stdio.h>
#include <math.h>
#define N 4
#define NumberOfProcessors 2
#define EPSILON 1e-5
float Matrix[N][N + 1] =
{
{ 1.0f, 0.1f, 0.1f, 0.1f, 1.0f },
{ 0.1f, 1.2f, 0.1f, 0.1f, 1.0f },
{ 0.2f, 0.1f, 1.0f, 0.1f, 1.0f },
{ 0.2f, 0.2f, 0.2f, 1.0f, 1.0f }
};
float NewX[N];
float CurX[N] = { 1.0, 1.0, 1.0, 1.0 };
void InitializeMatrix()
{
printf("Source Matrixn");
for (unsigned i = 0; i < N; i++)
{
for (unsigned j = 0; j <= N; j++)
{
// calculate (E - A)
if (i == j)
Matrix[i][j] = 1.0f - Matrix[i][j];
else
if (j < N)
17. SetEvent(State.evIterationFinished[Branch]);
if (Branch == 0)
{
WaitForMultipleObjects(NumberOfProcessors,
State.evIterationFinished, TRUE, INFINITE);
float d = -1;
for (i = 0; i < N; i++)
if (fabs(NewX[i] - CurX[i]) > d)
d = (float)fabs(NewX[i] - CurX[i]);
if (d < EPSILON)
Command = Stop;
memcpy(CurX, NewX, sizeof(NewX));
for (i = 0; i < NumberOfProcessors; i++)
SetEvent(State.Starters[i]);
}
}
}
int main(int argc, char* argv[])
{
UNREFERENCED_PARAMETER(argc);
UNREFERENCED_PARAMETER(argv);
InitializeMatrix();
HANDLE hThreads[NumberOfProcessors];
unsigned i, tid;
for (i = 0; i < NumberOfProcessors; i++)
{
State.Starters[i] =
CreateEvent(NULL, FALSE, TRUE, NULL);
State.evIterationFinished[i] =
CreateEvent(NULL, FALSE, FALSE, NULL);
}
18. for (i = 0; i < NumberOfProcessors; i++)
hThreads[i] = (HANDLE)_beginthreadex(
NULL, 0, ThreadFunction,
(void *)i, 0, &tid);
WaitForMultipleObjects(NumberOfProcessors, hThreads,
TRUE, INFINITE);
for (i = 0; i < NumberOfProcessors; i++)
{
CloseHandle(State.Starters[i]);
CloseHandle(State.evIterationFinished[i]);
CloseHandle(hThreads[i]);
}
for (i = 0; i < N; i++)
printf("x%d = %7.4fn", i, NewX[i]);
return 0;
}
19. 4. Решение системы линейных уравнений методом Гаусса
Метод Гаусса основан на последовательном исключении неизвестных. Пусть дана система линейных
алгебраических уравнений
Вычтем из второго уравнения системы первое, умноженное на такое число, чтобы уничтожился коэффициент
при . Затем таким же образом вычтем первое уравнение из третьего, четвёртого и т.д. Тогда исключатся все
коэффициенты первого столбца, лежащие ниже главной диагонали. Затем при помощи второго уравнения
исключим из третьего, четвёртого и т.д. уравнений коэффициенты второго столбца. Последовательно
продолжая этот процесс, исключим из матрицы все коэффициенты, лежащие ниже главной диагонали.
Запишем общие формулы процесса. Пусть проведено исключение коэффициентов из столбца. Тогда остались
такие уравнения с ненулевыми коэффициентами ниже главной диагонали:
Умножим k-ю строку на число
20. и вычтем из m-й строки. Первый элемент этой строки обратится в нуль, а остальные изменятся по формулам
Производя вычисления по этим формулам при всех указанных индексах, исключим элементы k-го столбца.
Будем называть такое исключение циклом процесса. Выполнение всех циклов называется прямым ходом
исключения. После выполнения прямого хода получим треугольную систему
с матрицей
Далее треугольная система решается обратным ходом по формулам
21. Оценим время выполнения описанного алгоритма. Не нарушая общности, будем предполагать, что первый
элемент первой строки не равен нулю и элементы на главной диагонали в ходе расчёта также не обращаются
в нуль.
Пусть , , , — время, затрачиваемое на сложение, вычитание, умножение и деление двух чисел
соответственно. Количество уравнений в системе обозначим .
Рассмотрим сначала прямой ход метода Гаусса. Первая строка обстается без изменений, поэтому e
исключение выполняется за время:
Тогда время, затраченное на выполнение прямого хода, будет равно:
Рассмотрим обратный ход метода Гаусса. Определение требует времени:
Соответственно, время выполнения обратного хода равно:
22. Итого, общее время
Рассмотрим параллельный алгоритм, реализующий метод Гаусса. Пусть имеется процессоров, причём для
простоты, , где — целое.
Процесс деления строк на коэффициенты перед независим и не требует информации от других ветвей.
Использование распределений горизонтальными или вертикальными полосами для данного метода ведет к
значительным простоям ветвей после исключения некоторого числа неизвестных. Поэтому распределим
вычисления таким образом, чтобы процессор обсчитывал строки с номерами
(распределение циклическими горизонтальными полосами с шириной полосы равной единице).
23. Рисунок 2. Схема параллельного метода Гаусса.
Так как и , то
,
Таким образом, если не учитывать простой процессоров вызванный (вообще говоря) неодинаковым
количеством обсчитываемых строк и неравномерностью самих вычислений, параллельный алгоритм работает
в K раз быстрее последовательного.
////////////////////////////////////////
// Приведение расширенной матрицы к диагональному виду
#include "stdafx.h"
25. unsigned Iteration = 0;
while (Iteration + 1 < N)
{
WaitForSingleObject(State.Starters[Branch], INFINITE);
for (unsigned i = Branch + Iteration + 1; i < N;
i += NumberOfProcessors)
{
float Resolver =
-Matrix[State.ResolveRow][Iteration] /
Matrix[i][Iteration];
for (unsigned j = Iteration; j <= N; j++)
Matrix[i][j] = Matrix[State.ResolveRow][j] +
Resolver * Matrix[i][j];
}
Iteration++;
// synchronization
SetEvent(State.evIterationFinished[Branch]);
if (Branch == 0)
{
WaitForMultipleObjects(NumberOfProcessors,
State.evIterationFinished, TRUE,
INFINITE);
State.ResolveRow++;
for (unsigned i = 0;
i < NumberOfProcessors; i++)
SetEvent(State.Starters[i]);
}
}
return 0;
}
int main(int argc, char* argv[])
{
UNREFERENCED_PARAMETER(argc);
26. UNREFERENCED_PARAMETER(argv);
InitializeMatrix();
State.ResolveRow = 0;
HANDLE hThreads[NumberOfProcessors];
unsigned i, j, tid;
for (i = 0; i < NumberOfProcessors; i++)
{
State.Starters[i] =
CreateEvent(NULL, FALSE, TRUE, NULL);
State.evIterationFinished[i] =
CreateEvent(NULL, FALSE, FALSE, NULL);
}
for (i = 0; i < NumberOfProcessors; i++)
hThreads[i] = (HANDLE)_beginthreadex(
NULL, 0, ThreadFunction, (void *)i, 0, &tid);
WaitForMultipleObjects(
NumberOfProcessors, hThreads, TRUE, INFINITE);
for (i = 0; i < NumberOfProcessors; i++)
{
CloseHandle(State.Starters[i]);
CloseHandle(State.evIterationFinished[i]);
CloseHandle(hThreads[i]);
}
printf("nTriangle Matrixn");
for (i = 0; i < N; i++)
{
for (j = 0; j <= N; j++)
printf("%7.4f ", Matrix[i][j]);
printf("n");
}
return 0;
}
27. 5. Вычисление скалярного произведения
Рассмотрим алгоритм вычисления скалярного произведения двух n-мерных векторов. Пусть даны два
вектора и . Их скалярное произведение вычисляется по формуле:
Оценим время, затрачиваемое на умножение векторов. Пусть — время, затрачиваемое на умножение двух
чисел, — время сложения двух чисел. Тогда время умножения двух n-мерных векторов равно:
Таким образом, сложность алгоритма Теперь рассмотрим параллельный алгоритм вычисления
скалярного произведения векторов. Обозначим количество процессоров в системе, причем ,
где .
Тогда каждый процессор будет вычислять координат результирующего вектора.
28. Рисунок 3. Распределение для скалярного произведения.
Оценим время работы параллельного алгоритма следующим образом:
Рассмотрим отношение
Ввиду того, что мы видим, что использование параллельного алгоритма позволяет решить задачу
быстрее. Более того, при , параллельный алгоритм вычисляет скалярное произведение векторов
быстрее последовательного почти в раз.
////////////////////////////////////////
// Параллельное вычисление скалярного произведения
#include "stdafx.h"
#include <process.h>
30. unsigned VectorSize)
{
if (!Vector1 || !Vector2)
return 0.0f;
unsigned ProcessorCount = GetNumberOfProcessors();
unsigned IntervalLength = VectorSize / ProcessorCount;
unsigned Remainder = VectorSize % ProcessorCount;
unsigned ProcessorsUsed =
(IntervalLength ? ProcessorCount : Remainder);
HANDLE *Handles = new HANDLE[ProcessorsUsed];
if (!Handles)
return 0.0f;
Interval *Intervals = new Interval[ProcessorsUsed];
if (!Intervals)
{
delete Handles;
return 0.0f;
}
// Nonsignaled manual-reset event
HANDLE evStart = CreateEvent(NULL, TRUE, FALSE, NULL);
unsigned From = 0;
unsigned i;
for (i = 0; i < ProcessorCount; i++)
{
unsigned To = From + IntervalLength;
if (Remainder)
To++, Remainder--;
if (To == From)
continue;
unsigned tid;
Intervals[i].First = From;
Intervals[i].To = To;
31. Intervals[i].evStart = evStart;
Intervals[i].hThread = (HANDLE)
_beginthreadex(NULL, 0, ThreadFunction,
&Intervals[i], 0, &tid);
From = To;
}
for (i = 0; i < ProcessorsUsed; i++)
{
Intervals[i].Vector1 = Vector1;
Intervals[i].Vector2 = Vector2;
Handles[i] = Intervals[i].hThread;
}
SetEvent(evStart);
WaitForMultipleObjects(ProcessorsUsed, Handles, TRUE,
INFINITE);
float Result = 0.0f;
for (i = 0; i < ProcessorsUsed; i++)
{
Result += Intervals[i].Result;
CloseHandle(Intervals[i].hThread);
}
CloseHandle(evStart);
delete[] Intervals;
delete[] Handles;
return Result;
}
unsigned __stdcall ThreadFunction(void *pData)
{
if (pData)
{
Interval &iv = *(Interval *)pData;
WaitForSingleObject(iv.evStart, INFINITE);
for (unsigned i = iv.First; i < iv.To; i++)
32. iv.Result += iv.Vector1[i] * iv.Vector2[i];
}
return 0;
}
unsigned GetNumberOfProcessors()
{
DWORD dwProcessAffinityMask, dwSystemAffinityMask;
unsigned n = 0;
if (GetProcessAffinityMask(GetCurrentProcess(),
&dwProcessAffinityMask,
&dwSystemAffinityMask))
{
for (DWORD dwMask = 0x00000001; dwMask;
dwMask <<= 1)
if (dwMask & dwProcessAffinityMask)
n++;
}
else
n = 1;
return n;
}
33. 6. Умножение матриц
Задача умножения матриц является базовой макрооперацией для многих задач линейной алгебры. Поэтому
эффективный параллельный алгоритм умножения матриц позволяет значительно увеличить размерность
подобных задач без увеличения времени их решения. Пусть даны две матрицы, и ., произведение
которых необходимо вычислить. Элементы результирующей матрицы определяются по формуле
Оценим время выполнения последовательного алгоритма. Пусть — время, затрачиваемое на умножение
двух чисел, — время сложения двух чисел. Время, затрачиваемое на вычисление одного элемента
результирующей матрицы . В результирующей матрице содержится элементов,
поэтому общее время выполнения умножения матриц равно
Обозначим Отсюда следует, что .
Рассмотрим параллельный алгоритм умножения матриц и оценим время его работы.
34. Пусть имеется процессоров, причём, , где — целое. Распараллелим вычисления так, чтобы
каждый процессор вычислял элементов результирующей матрицы. Тогда суммарное время выполнения
можно оценить следующим образом:
Обозначим Сравнивая и , получим: Имеем, что время, затрачиваемое на
умножение матриц с помощью параллельного алгоритма, в раз меньше, чем при использовании
последовательного.
Рассмотрим один из способов распараллеливания алгоритма. Пронумеруем элементы результирующей
матрицы по следующему правилу (нумерация элементов, а также строк и столбцов в данном случае ведётся с
нуля):
Вычисления распределим так, чтобы первый процессор вычислял первые элементов результирующей
матрицы, второй — следующие и т.д. Таким образом, конечная и левая исходная матрица получаются
распределёнными горизонтальными полосами, а правая исходная матрица — вертикальными полосами.
35. Рисунок 4. Схема распределения работ при параллельном умножении матриц.
Рассмотрим случай, когда (количество процессоров больше, чем элементов в результирующей
матрице). Незадействованные процессоров можно использовать для ускорения вычисления
отдельных элементов результирующей матрицы. При этом следует использовать способ распараллеливания,
подобный использованному при вычислении скалярного произведения векторов.
////////////////////////////////////////
// Параллельное умножение матриц
#include "windows.h"
#include "process.h"
#include "stdio.h"
#define M 3
#define N 4
#define NumberOfProcessors 3
int A[M][N];
int B[N][M];
int C[M][M];
void InititalizeMatices()
{
unsigned i, j, n;
36. printf("nMatrix A:n");
for (i = 0, n = 1; i < M; i++)
{
for (j = 0; j < N; j++, n++)
{
A[i][j] = n;
printf("%4d ", n);
}
printf("n");
}
printf("nMatrix B:n");
for (i = 0, n = 1; i < N; i++)
{
for (j = 0; j < M; j++, n++)
{
B[i][j] = n;
printf("%4d ", n);
}
printf("n");
}
}
unsigned __stdcall ThreadFunction(void *pData)
{
unsigned Branch = (unsigned)pData;
unsigned Start = M / NumberOfProcessors * Branch;
unsigned End = M / NumberOfProcessors * (Branch + 1);
for (unsigned i = Start; i < End; i++)
for (unsigned j = 0; j < M; j++)
{
int Value = A[i][0] * B[0][j];
for (unsigned k = 1; k < N; k++)
Value += A[i][k] * B[k][j];
C[i][j] = Value;
37. }
return 0;
}
int main(int argc, char* argv[])
{
UNREFERENCED_PARAMETER(argc);
UNREFERENCED_PARAMETER(argv);
assert(M % NumberOfProcessors == 0);
InititalizeMatices();
HANDLE hThreads[NumberOfProcessors];
unsigned i, j, n, tid;
for (i = 0; i < NumberOfProcessors; i++)
hThreads[i] = (HANDLE)_beginthreadex(NULL, 0,
ThreadFunction, (void *)i, 0, &tid);
WaitForMultipleObjects(NumberOfProcessors, hThreads, TRUE,
INFINITE);
for (i = 0; i < NumberOfProcessors; i++)
CloseHandle(hThreads[i]);
printf("nMatrix C = A * B:n");
for (i = 0, n = 1; i < M; i++)
{
for (j = 0; j < M; j++, n++)
printf("%4d ", C[i][j]);
printf("n");
}
return 0;
}
38. Заключение
Надеемся, статья помогла Вам немного лучше разобраться в вопросах параллельного программирования, а
приведенные примеры наглядно продемонстрировали некоторые параллельные алгоритмы. Желаем Вам
успехов в создании эффективных программных решений.
Литература
Элементы параллельного программирования / В.А. Вальковский, В.Е. Котов, А.Г. Марчук, Н.Н. Миренков;
под ред. В.Е. Котова. — М.: Радио и связь, 1983. — 240с.,интеграл.
Алгоритмы, математическое обеспечение и архитектура многопроцессорных вычислительных систем /
Под ред. В.Е. Котова и И. Миклошко — М.: Наука, 1982. — 336 с.
Миренков Н.Н. Параллельное программирование для многомодульных вычислительных систем. — М.:
Радио и связь, 1989. — 320с.: ил. — ISBN 5-256-00196-5
Шихаев К.Н. Разностные алгоритмы параллельных вычислительных процессов. — М.: Радио и связь,
1982. — 136с., ил.
Вальковский В.А. Распараллеливание алгоритмов и программ. Структурный подход. М.: Радио и связь,
1989. —176с., ил. — ISBN 5-256-00195-7.
39. Об Авторах
Миронов Антон Александрович
Занимается вопросами создания и использования высокопроизводительных параллельных алгоритмов. Один
из ведущих разработчиков в компании Developer Express Inc.
Карпов Андрей Николаевич
Занимается вопросами создания программных решений в области повышения качества и быстродействия
ресурсоемких приложений. Является одним из авторов статического анализатора Viva64 иVivaMP,
предназначенных для верификации 64-битного и параллельного Си/Си++ кода.