Как стать автором
Обновить

Комментарии 11

Честно говоря, не очень понятно, зачем такие сложности — расширение языка. Да и чем подход радикально отличается от "классического" распараллеливания на общем пуле потоков (кроме того, что это делается вручную, а не автоматически)? Какой-то выделенной поддержкой векторных вычислителей и тем, что все детали реализации очереди сокрыты от пользователя? Поясните, пожалуйста.

Классическое распараллеливание на общем пуле потоков, обычно, тоже требует указания одной-двух директив (как в OpenMP) или, например, обертки Вашего кода в некий класс-пул, или вызова специальных функций, иными словами, обычно требуются дополнительные «ручные» манипуляции. С этой точки зрения предлагаемый подход, как минимум, не сложнее. При этом он, думаю, более органичен (и, не исключено, потенциально более эффективно реализуем компилятором) для распараллеливания обработки таких сложных структур данных, как граф (сеть, дерево и т.д.), а еще, возможно, больших таблиц. Кроме того, да, действительно, один и тот же прием программирования (с не очень большими декларативными изменениями) используется, вообще говоря, как для обычных многоядерных ЦПУ, так и для многоядерных видеокарт — это повышает переносимость кода и облегчает гибридное распараллеливание CPU+GPU. Применение же топологий позволяет дополнительно организовать распараллеливание на кластере. Все это, в комплексе, думаю оправдывает подход в смысле распараллеливания. Что же касается последовательного программирования, то там ПППВ/ФППВ — просто еще один способ записи некоторых алгоритмов, позволяющий не заботиться, например, о явном вводе переменной-очереди. Может быть, в таком случае это уже «синтаксический сахар».

Сразу скажу, что я не являюсь сколь-нибудь квалифицированным специалистом по части "гетерогенных" вычислений (на кластере, на GPU и т.д.). Вот несколько мыслей, которые мне удалось из прочитенного и понятого сформулировать.


  1. "Инвазивный подход" требует изменения синтаксиса языка, наличие транслятора/препроцессора/особую поддержку в компиляторе. Это снижает управляемость тем, что происходит за занавесом, со стороны программиста. Плохо продуманные синтаксические конструкции могут породить другие синтаксические конструкции, чтобы закрыть дыры в первых.


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


  3. Не понятно, как вообще компилятор / препроцессор будет организовывать работу в кластере.

По поводу оптимизаций компилятора сказать ничего не могу, но как-то интуитивно — особой разницы не будет. Поле для оптимизаций ведь у нас не очень большое — мне только стек и видится (первый пример в статье, например). А эмуляция стека в коде и "нативный" стек в принципе отличаются только тем, что при переполнении стековой памяти легко получить stack overflow. Поправьте, если несу бредятину)

«Инвазивный подход» все же упрощает распараллеливание и, экономя время и силы на программирование, при грамотной реализации в компиляторе будет вполне адекватен. Что же касается повышения эффективности/управляемости путем ручного распараллеливания, то я, в общем, конечно согласен. Предложенный подход не отрицает сосуществования с такими ручными средствами, они даже приветствуются иногда (в дополнение), если требуется выжать все, что только возможно.
Что же касается организации компилятором работы в кластере (при работе с топологиями из ПППВ), то у меня подход вполне стандартный: программа в неизменном виде исполняется на каждом узле, каждый узел внутри программы идентифицируется номером, в зависимости от номера программой выполняется тот или иной фрагмент кода. В качестве низкоуровневого интерфейса транслятор использует MPI.
Что же касается оптимизаций в компиляторе, то сравню с OpenMP. Например, если говорить о реализации обработки дерева, то можно, конечно написать на OpenMP 3.0 рекурсивную функцию, которая будет порождать подзадачи и затем ставить барьер на ожидание их завершения. Это две директивы, при этом транслятор, скорее всего, будет генерировать для каждой из них независимый код. В предложенном подходе можно написать ПППВ, причем потребуется одна директива распараллеливания, причем компилятор работает с ПППВ/ФППВ стандартным образом, который при желании можно попытаться довести до совершенства. Поэтому мне кажется, что в случае OpenMP у транслятора меньше информации для наиболее оптимальной организации параллельной работы.

Ну, возможно, Вы и правы. За счет сужения области применения получаем более оптимальную трансляцию. (Но, опять же, не компиляцию.)


Честно говоря, я всегда был убежден, что синтаксические конструкции — просто синтаксический сахар. Те же async/await в Boost прекрасно "эмулируются" переключением контекстов (Boost.Context)...


Надо будет как-нибудь попробовать Ваш инструмент в деле, чтобы не разглагольствовать попусту)

Да, хотелось бы взглянуть на результат работы. Вы его описываете-описываете) Надо же пощупать. Что же это за такие "еще некоторые интересные вещи"?

Работоспособную (хотя и не последнюю) версию транслятора можно скачать и посмотреть на моем сайте в разделе «Программы». Она написана на Free Pascal, простовата и не очень удобна, работает из командной строки (Linux, Windows), генерирует C++-код, который при компиляции требует OpenMP, а также может (в зависимости от транслируемой программы) требовать MPI и/или OpenCL. Что же касается интересностей, то это немного порождающего программирования, некоторые полезные применения ПППВ/ФППВ при использовании статического плана, «отчуждаемый» план и еще некоторые тонкости. Подробно (хотя и несколько тяжеловесно), если захотите, можно посмотреть в книге.
Я бы убрал спецификацию исключений, зачем лишний мусор писать?
В данном случае throw(...) — это не указание исключений, а спецификация параметров «принимающей» процедуры при работе в топологии. Эту часть конструкции можно не писать, если список параметров «передающей» процедуры совпадает со списком параметров «принимающей» процедуры.
Т.е. это будет обработано и вырезано препроцессором? А если в коде есть функции со спецификацией исключений, то её не сломает препроцессинг?
Да, обработано и вырезано. Что же касается пересечения со спецификацией исключения, то теоретически путаницы не будет, поскольку спецификация исключений может быть: throw(), throw(...), throw(тип), а спецификация параметров принимающей процедуры: throw(тип имя [, тип имя ...]). Однако в текущей демо-версии транслятора путаница возникнуть может (я проверю, если есть — поправлю).
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории