Здесь показана простая программа на Fortran - PSDOT - для вычисления точечного произведения. Программа вычисляет точечное произведение массивов X и Y. В первую очередь, в PSDOT вызываются PVMFMYTID() и PVMFPARENT(). Вызов PVMFPARENT вернет PVMNOPARENT, если задача не была ранее порождена другой задачей ПВМ. Если это случай, когда PSDOT - ведущая и, следовательно, должна породить отдельные рабочие копии PSDOT, то у пользователя запрашивается число рабочих процессов и длина векторов для вычисления. Каждый порождаемый процесс будет принимать элементов X и Y, где - длина векторов, а - количество процессов, используемых при вычислении. Если не делится на нацело, то ведущий будет вычислять точечное произведение "дополнительных элементов". Подпрограммой SGENMAT случайным образом генерируются значения X и Y. После этого, PSDOT порождает своих копий и передает каждой новой задаче часть массивов X и Y. Каждое сообщение содержит размеры подмассивов и, собственно, сами подмассивы. После того, как ведущий породил рабочие процессы и передал подвекторы, он вычисляет точечное произведение своей порции X и Y. Затем ведущий процесс принимает остальные локальные точечные произведения от рабочих процессов. Обратите внимание на то, что при вызове PVMFRECV как параметр-идентификатор задачи используется специальный символ (-1). Это говорит о том, что сообщение от "любой" задачи будет устраивать принимающую сторону. Применение специального символа таким образом может привести к "гибридизации". Но, в данном случае, "гибридизация" не создаст проблему - т.к. сложение по своей природе коммутативно. Другими словами, совершенно не важно, в каком порядке складываются частичные суммы, полученные от рабочих. Если кто-то не уверен, что "гибридизация" не приведет к нежелательным программным эффектам, то ему желательно избегать ее возникновения.
Как только ведущий принял все локальные точечные произведения и просуммировал их в одно глобальное точечное произведение, он вычисляет полное точечное произведение уже локально. Один результат вычитается из второго, а разница между величинами выводится на экран. Несущественная разница вполне ожидаема, т.к. существуют погрешности, связанные с округлениями чисел с плавающей точкой.
Если программа PSDOT -это рабочий, то она принимает содержащее подмассивы X и Y сообщение от ведущего процесса. Она вычисляет точечное произведение этих подмассивов и передает результат назад ведущему процессу. В интересах краткости, сюда не включили подпрограммы SGENMAT и SDOT.
Программа-пример PSDOT_F:
*
* PSDOT параллельно реализует внутреннее (или точечное) произведение:
* векторы X и Y сначала находятся на ведущей станции, которая затем
* устанавливает виртуальную машину, раздает данные и задания, и,
* наконец, суммирует локальные результаты с целью получения
* глобального внутреннего произведения.
*
* .. Внешние подпрограммы ..
EXTERNAL PVMFMYTID, PVMFPARENT, PVMFSPAWN, PVMFEXIT, PVMFINITSEND
EXTERNAL PVMFPACK, PVMFSEND, PVMFRECV, PVMFUNPACK, SGENMAT
*
* .. Внешние функции ..
INTEGER ISAMAX
REAL SDOT
EXTERNAL ISAMAX, SDOT
*
* .. Внутренние функции ..
INTRINSIC MOD
*
* .. Параметры ..
INTEGER MAXN
PARAMETER ( MAXN = 8000 )
INCLUDE 'fpvm3.h'
*
* .. Скаляры ..
INTEGER N_ LN_ MYTID_ NPROCS_ IBUF_ IERR
INTEGER I, J, K
REAL LDOT, GDOT
*
* .. Массивы ..
INTEGER TIDS(0:63)
REAL X(MAXN), Y(MAXN)
*
* Регистрация в ПВМ и получение идентификаторов задач своего и ведущего
* процессов.
*
CALL PVMFMYTID( MYTID )
CALL PVMFPARENT( TIDS(0) )
*
* Нужно ли порождать другие процессы (Это - ведущий процесс).
*
IF ( TIDS(0) .EQ. PVMNOPARENT ) THEN
*
* Получение исходных данных.
*
WRITE(*.*) 'Сколько процессов нужно создать (1-64)?'
READ(*.*) NPROCS
WRITE(*,2000) MAXN
READ(*.*) N
TIDS(0) = MYTID
IF ( N .GT. MAXN ) THEN
WRITE(*.*) 'N слишком велико. Увеличьте параметр MAXN'//
$ 'для этого случая.'
STOP
END IF
*
* LN - это количество элементов точечного произведения для локальной
* обработки. Все имеют одинаковое количество, а "лишние" элементы
* достаются ведущему. "Общее" количество элементов и хранится в J.
*
J = N / NPROCS
LN = J + MOD(N, NPROCS)
I = LN + 1
*
* Генерирование случайных X и Y.
*
CALL SGENMAT( N, 1, X, N, MYTID, NPROCS, MAXN, J )
CALL SGENMAT( N, 1, Y, N, I, N, LN, NPROCS )
*
* Обход всех рабочих процессов.
*
DO 10 K = 1, NPROCS-1
*
* Порождение процесса и проверка на ошибки.
*
CALL PVMFSPAWN( 'psdot', 0, 'anywhere', 1, TIDS(K), IERR )
IF (IERR .NE. 1) THEN
WRITE(*.*) 'ERROR, невозможно создать процесс #',K,
$ '. Dying . . .'
CALL PVMFEXIT( IERR )
STOP
END IF
*
* Рассылка исходных данных.
*
CALL PVMFINITSEND( PVMDEFAULT, IBUF )
CALL PVMFPACK( INTEGER4, J, 1, 1, IERR )
CALL PVMFPACK( REAL4, X(I), J, 1, IERR )
CALL PVMFPACK( REAL4, Y(I), J, 1, IERR )
CALL PVMFSEND( TIDS(K), 0, IERR )
I = I + J
10 CONTINUE
*
* Вычисление ведущим своей части точечного произведения.
*
GDOT = SDOT( LN, X, 1, Y, 1 )
*
* Получение локальных точечных произведений и их сложение с целью
* формирования глобального.
*
DO 20 K = 1, NPROCS-1)
CALL PVMFRECV( -1, 1, IBUF )
CALL PVMFUNPACK( REAL4, LDOT, 1, 1, IERR )
GDOT = GDOT + LDOT
20 CONTINUE
*
* Вывод на экран результатов.
*
WRITE(*,*) ' '
WRITE(*,*) '<x,y> = ',GDOT
*
* "Последовательное" вычисление точечного произведения и его вычитание
* из "распределенного" точечного произведения - с целью проверки
* на допустимость уровня ошибок.
*
LDOT = SDOT( N, X, 1, Y, 1 )
WRITE(*,*) '<x,y> : последовательное произведение. <x,y>^ : '//
$ 'распределенное произведение.'
WRITE(*,*) '| <x,y> - <x,y>^ | = ',ABS(GDOT = LDOT)
WRITE(*,*) 'Завершено.'
*
* Является ли этот процесс рабочим.
*
ELSE
*
* Прием исходных данных.
*
CALL PVMFRECV( TIDS(0), 0, IBUF )
CALL PVMFUNPACK( INTEGER4, LN, 1, 1, IERR )
CALL PVMFUNPACK( REAL, X, LN, 1, IERR )
CALL PVMFUNPACK( REAL, Y, LN, 1, IERR )
*
* Вычисление локального точечного произведения и передача его
* ведущему.
*
LDOT = SDOT( LN, X, 1, Y, 1 )
CALL PVMFINITSEND( PVMDEFAULT, IBUF )
CALL PVMFPACK( REAL4, LDOT, 1, 1, IERR )
CALL PVMFSEND( TIDS(0), 1, IERR )
END IF
*
CALL PVMFEXIT( 0 )
*
1000 FORMAT(I10, 'Успешно порожден процесс #',I2,', TID =',I10)
2000 FORMAT('Введите длину перемножаемых векторов (1 -',I7,'):')
STOP
*
* End program PSDOT
*
END