Вероятно, наиболее разумный способ сделать это — сделать так, чтобы один из процессов заранее подсчитал общее количество файлов, транслировал его, а затем каждый сделал «свои» файлы:
program processfiles
use mpi
implicit none
integer :: rank, comsize, ierr
integer :: nfiles
character(len=6) :: prefix="result"
character(len=4) :: suffix=".bin"
character(len=50) :: filename
integer :: i
integer :: locnumfiles, startnum, endnum
logical :: exists
call MPI_Init(ierr)
call MPI_Comm_size(MPI_COMM_WORLD, comsize, ierr)
call MPI_Comm_rank(MPI_COMM_WORLD, rank, ierr)
! rank zero finds number of files
if (rank == 0) then
nfiles = 0
do
write(filename,FMT='(A,I0,A)'), prefix, nfiles+1, suffix
inquire(file=trim(filename),exist=exists)
if (not(exists)) exit
nfiles = nfiles + 1
enddo
endif
! make sure everyone knows
call MPI_Bcast(nfiles, 1, MPI_INTEGER, 0, MPI_COMM_WORLD, ierr)
if (nfiles /= 0) then
! calculate who gets what file
locnumfiles = nfiles/comsize
if (locnumfiles * comsize /= nfiles) locnumfiles = locnumfiles + 1
startnum = locnumfiles * rank + 1
endnum = startnum + locnumfiles - 1
if (rank == comsize-1) endnum = nfiles
do i=startnum, endnum
write(filename,FMT='(A,I0,A)'), prefix, i, suffix
call processfile(rank,filename)
enddo
else
if (rank == 0) then
print *,'No files found; exiting.'
endif
endif
call MPI_Finalize(ierr)
contains
subroutine processfile(rank,filename)
implicit none
integer, intent(in) :: rank
character(len=*), intent(in) :: filename
integer :: unitno
open(newunit=unitno, file=trim(filename))
print '(I4,A,A)',rank,': Processing file ', filename
close(unitno)
end subroutine processfile
end program processfiles
А затем простой тест:
$ seq 1 33 | xargs -I num touch "result"num".bin"
$ mpirun -np 2 ./processfiles
0: Processing file result1.bin
0: Processing file result2.bin
0: Processing file result3.bin
0: Processing file result4.bin
0: Processing file result5.bin
0: Processing file result6.bin
1: Processing file result18.bin
0: Processing file result7.bin
0: Processing file result8.bin
1: Processing file result19.bin
0: Processing file result9.bin
1: Processing file result20.bin
0: Processing file result10.bin
1: Processing file result21.bin
1: Processing file result22.bin
0: Processing file result11.bin
1: Processing file result23.bin
0: Processing file result12.bin
1: Processing file result24.bin
1: Processing file result25.bin
0: Processing file result13.bin
0: Processing file result14.bin
1: Processing file result26.bin
1: Processing file result27.bin
0: Processing file result15.bin
0: Processing file result16.bin
1: Processing file result28.bin
1: Processing file result29.bin
1: Processing file result30.bin
0: Processing file result17.bin
1: Processing file result31.bin
1: Processing file result32.bin
1: Processing file result33.bin
Обновлено для добавления дополнительного вопроса OpenMP:
Таким образом, в первом цикле вычисляется количество файлов до начала параллельной обработки файлов. Этот подсчет файлов должен быть выполнен до того, как может произойти параллельная обработка файлов, поскольку в противном случае невозможно разделить работу между процессорами; вам нужно знать, сколько «рабочих единиц» будет, прежде чем разбивать работу. (Это не единственный способ сделать что-то, но самый простой).
Точно так же циклы OMP DO
требуют достаточно структурированных циклов — должен быть простой цикл, такой как do i=1,n
, который затем можно легко разбить между потоками. n
не нужно компилировать, и приращение даже не обязательно должно быть единицей, но оно должно быть таким, что можно знать наверняка до фактического выполнения цикла. Так, например, вы не можете выйти из цикла по какой-то внешней причине (например, из-за отсутствия файла).
Итак, что вы хотели бы сделать с OpenMP, так это сделать тот же подсчет файлов и оставить его в покое, но затем в цикле processing использовать параллельную конструкцию do. Итак, после удаления материала MPI у вас будет что-то вроде:
do
write(filename,FMT='(A,I0,A)'), prefix, nfiles+1, suffix
inquire(file=trim(filename),exist=exists)
if (.not.exists) exit
nfiles = nfiles + 1
enddo
if (nfiles /= 0) then
!$OMP PARALLEL SHARED(nfiles,prefix,suffix) PRIVATE(i,thread,filename)
thread = omp_get_thread_num()
!$OMP DO
do i=1, nfiles
write(filename,FMT='(A,I0,A)'), prefix, i, suffix
call processfile(thread,filename)
enddo
!$OMP END DO
!$OMP END PARALLEL
else
print *,'No files found; exiting.'
endif
но все остальное было бы то же самое. И снова, если вы хотите обрабатывать файлы «встроенно» (например, не в подпрограмме), вы должны поместить код обработки файлов туда, где находится строка «call processfile()».
person
Jonathan Dursi
schedule
10.04.2011