Знакомство с Coarray Fortran: будем параллельны?

в 5:02, , рубрики: Без рубрики

Очень давно хотел написать о том, на какой стадии сейчас находится один из «прародителей» популярных сегодня языков программирования. Да, я говорю о Фортране. Попытаюсь разрушить стереотип, который существует в умах многих разработчиков – что Фортран древний язык без каких либо перспектив, и уж точно никто на нём уже не пишет. Наоборот, он очень активно эволюционирует и уже давно предлагает богатый набор различных функциональностей, закреплённых в стандартах, вполне, кстати, сопоставимых с тем же С/С++.
От «старого» 77-го Фортрана осталось уже не так и много… в 95 стандарте мы могли вполне себе создавать свои типы данных, динамически выделять и очищать память, работать с указателями, перегружать функции и операторы и много чего ещё. По сути, от С своим набором средств он отличается несильно. Тем не менее, я не хочу пытаться сравнивать языки – это вопрос философии. Скажу только, что фортрановский компилятор Intel пользуется очень большим спросом, и, собственно, приобретается даже активнее, чем тот же С++.
Цель же данного поста – рассказать о текущем состоянии дел. Собственно, Фортран на сегодняшний день — параллельный язык, и стал он таковым после принятия стандарта Fortran 2008, в котором появились Coarray’и.

Итак, обо всё по порядку. За основу была взята модель программирования SPMD (Single Program MultipleData). Если вы знакомы с MPI, то суть та же – мы пишем наше приложение, копии которого будут выполняться определенное количество раз параллельно. При этом у каждой копии имеются свои локальные данные. Те данные, к которым необходим доступ из разных копий, описываются с помощью специального синтаксиса, именуемого как Coarray.

Для понимания достаточно привести простой Hello World пример:

program hello
write(*,*) "Hello world"
end program hello

Собственно, самый обычный код. Вот только скомпилировав его с ключиком –coarray (компилятором Intel), мы увидим «приветы» из нескольких разных копий программы, или, в терминах Coarray, из разных Image’ей (образов). Причём их число можно контролировать, например, через ключ –coarray-num-images=x, или переменную окружения FOR_COARRAY_NUM_IMAGES. Понятно, что существует способ определять, в каком образе происходит выполнение. Усложним наш пример:

program hello_image
write(*,*) "Hello from image ", this_image(), "out of ", num_images()," total images“
end program hello_image

После запуска мы увидим что-то похожее на это:

Hello from image            1 out of            4  total images
Hello from image            4 out of            4  total images
Hello from image            2 out of            4  total images
Hello from image            3 out of            4  total images

Очевидно, что наше приложение было выполнено 4 раза (4 копии/образа). Имея эти данные о Coarray, мы в принципе, уже способны создавать параллельные приложения.

Вот только весьма бестолковые, потому что нет ответа на главный вопрос – как же быть с данными? Для этого вводят очень простой и понятный синтаксис:

real, codimension[*] :: x
real :: y[*]

Квадратные скобки говорят нам о том, что мы используем Сoarray.
В данном примере это просто скаляры, которые всё так же доступны в каждой копии программы. Но теперь мы можем обратиться к значению этого скаляра в нужной нам копии (образе).

Например, написав y[2] мы обратимся к значению y в образе 2. Это открывает нам возможности для «настоящей» параллельной работы с данными.

Естественно, существует ряд логичный ограничений, накладываемых на Сoarray’и, как, например, любая попытка связать объект Сoarray с другим объектом через указатели, или передача объектов Сoarray в С код.
Давайте рассмотрим ещё несколько примеров, считая, что мы уже объявили ранее переменную x как Сoarray:

x = 42.0

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

x[3] = 42.0  ! задаёт значение х равное 42 в образе 3
x = x[1]  ! присваиваем локальной для текущего образа переменной х значение из образа 1
x[i] = x[j]  !присваиваем переменной х в образе I значение переменной х из образа j

Что хорошо в Coarray, так это то, что в отличие от чистого MPI, мы не заботимся о посылке или приеме сообщений. Всё это на плечах реализации (которая уже и использует тот же MPI). Но мы «над» этим. Кроме того, код будет работать как на системах с распределённой памятью, так и на системах с общей. Достаточно только поменять ключ на coarray=shared или coarray=distributed.

Раз уж у нас появились данные в разных копиях нашей программы, логично предположить, что должны быть и средства для их синхронизации. Конечно, они имеются. Это, например, конструкция SYNC ALL, синхронизирующая все образы. Есть ещё и SYNC IMAGES(), позволяющая синхронизировать только определенные образы.

Ещё один пример:

integer, codimension[*] :: fact
integer :: i, factorial
fact = this_image() 
SYNC ALL           
if ( this_image() == 1 ) then
   factorial = 1
   do i = 1, num_images()
     factorial = factorial * fact[i]
   end do
   write(*, *) num_images(), 'factorial is ', factorial
end if

Естественно, не самый быстрый способ посчитать факториал, зато хорошо иллюстрирующий суть работы с Сoarray.

Для начала, объявляем fact как Сoarray, и далее в каждом образе мы присваиваем значение, равное номеру образа. Перед тем, как мы перемножим все значения, нужно убедиться, что они уже присвоены, поэтому используем SYNC ALL. И в образе с номером 1, таком якобы «мастер-образе», вычисляем факториал.

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

Я же заканчиваю своё краткое описание относительно «новых плюшек» из последнего принятого стандарта. Надеюсь, было не очень скучно смотреть Фортрановский код. Если же отзывы покажут обратное и проснётся живой интерес по данной теме, то я не откажу вам в удовольствии и продолжу тему. А сейчас всем большое спасибо за внимание.

Автор: ivorobts

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js