【问题标题】:MPI write to file sequentiallyMPI 顺序写入文件
【发布时间】:2014-06-15 04:30:04
【问题描述】:

我正在用我的 fortran CFD 求解器编写一个并行 VTK 文件 (pvti)。该文件实际上只是每条数据的所有单个文件的列表。运行 MPI,如果我让每个进程将其单个文件的名称写入标准输出

print *, name

然后我得到每个文件的漂亮列表,即

block0.vti
block1.vti
block2.vti

这正是我想要的那种列表。但是如果我写一个文件

write(9,*) name

然后我在文件中只得到一个输出。有没有一种简单的方法可以在不传输数据的情况下复制它的标准输出版本?

【问题讨论】:

  • 就我个人而言,我只会从主图像中编写这样的头文件,没有关于所有其他图像的所有必需信息吗?
  • @VladimirF,是的。 “名称”是重要的,编码块位置和大小以及其他内容。但是,我认为 MPI-IO 在我的特定情况下不值得。

标签: fortran mpi paraview mpi-io


【解决方案1】:

您可以尝试调整以下使用 MPI-IO 的方法,这确实是确保来自多个进程的有序文件的唯一方法。它确实假设行尾字符并且所有行的长度相同(如果需要,用空格填充)但我认为就是这样。

Program ascii_mpiio

  ! simple example to show MPI-IO "emulating" Fortran 
  ! formatted direct access files. Note can not use the latter
  ! in parallel with multiple processes writing to one file
  ! is behaviour is not defined (and DOES go wrong on certain
  ! machines)

  Use mpi

  Implicit None

  ! All the "lines" in the file will be this length
  Integer, Parameter :: max_line_length = 30

  ! We also need to explicitly write a carriage return. 
  ! here I am assuming  ASCII
  Character, Parameter :: lf = Achar( 10 )

  ! Buffer to hold a line
  Character( Len = max_line_length + 1 ) :: line

  Integer :: me, nproc
  Integer :: fh
  Integer :: record
  Integer :: error
  Integer :: i

  ! Initialise MPI
  Call mpi_init( error )
  Call mpi_comm_rank( mpi_comm_world, me   , error )
  Call mpi_comm_size( mpi_comm_world, nproc, error )

  ! Create a MPI derived type that will contain a line of the final
  ! output just before we write it using MPI-IO. Note this also
  ! includes the carriage return at the end of the line.
  Call mpi_type_contiguous( max_line_length + 1, mpi_character, record, error )
  Call mpi_type_commit( record, error )

  ! Open the file. prob want to change the path and name
  Call mpi_file_open( mpi_comm_world, '/home/ian/test/mpiio/stuff.dat', &
       mpi_mode_wronly + mpi_mode_create, &
       mpi_info_null, fh, error )

  ! Set the view for the file. Note the etype and ftype are both RECORD,
  ! the derived type used to represent a whole line, and the displacement
  ! is zero. Thus
  ! a) Each process can "see" all of the file
  ! b) The unit of displacement in subsequent calls is a line. 
  !    Thus if we have a displacement of zero we write to the first line,
  !    1 means we write to the second line, and in general i means
  !    we write to the (i+1)th line
  Call mpi_file_set_view( fh, 0_mpi_offset_kind, record, record, &
       'native', mpi_info_null, error )

  ! Make each process write to a different part of the file
  Do i = me, 50, nproc
     ! Use an internal write to transfer the data into the
     ! character buffer
     Write( line, '( "This is line ", i0, " from ", i0 )' ) i, me
     !Remember the line feed at the end of the line
     line( Len( line ):Len( line ) ) = lf
     ! Write with a displacement of i, and thus to line i+1
     ! in the file
     Call mpi_file_write_at( fh, Int( i, mpi_offset_kind ), &
          line, 1, record, mpi_status_ignore, error )
  End Do

  ! Close the file
  Call mpi_file_close( fh, error )

  ! Tidy up
  Call mpi_type_free( record, error )

  Call mpi_finalize( error )

End Program ascii_mpii

另外请注意,您只是幸运地使用了标准输出“解决方案”,但不能保证您得到很好的排序。

【讨论】:

  • 谢谢。在我检查之前,你知道为什么打印功能对我有用,但并非总是如此吗?引擎盖下发生了什么?
  • 没什么特别的,只是一切都是异步发生的。不仅是程序,还有程序与您正在写入的屏幕或文件之间的 I/O 层。因此,即使您同步以尝试确保程序中的排序,您也无法同步下面的所有图层,因此排序可能会丢失。 MPI-I/O 是管理此问题的唯一明智方法。
  • 所以答案是“不,没有一种简单的方法可以用 MPI-IO 来做到这一点。”在我的情况下,重新计算 0 级的“名称”并让它连续打印要容易得多。但是,您的解决方案可能会帮助遇到更困难问题或需要更好扩展的其他人。
【解决方案2】:

除了将来自不同等级的写入很好地混合之外,您的问题是 Fortran OPEN 语句可能会将文件截断为零长度,从而消除以前的内容而不是附加到它。我和 Vladimir F 一起讨论这个问题,并且只会将此文件写入 0 级。有几种可能的情况,其中一些在此处列出:

  • 每个等级写一个单独的VTK文件,顺序跟随等级或实际顺序不重要。在这种情况下,您可以简单地使用从 0#ranks-1 的 rank 0 中的 DO 循环来生成整个列表。

  • 每个等级写入一个单独的VTK文件,但顺序不遵循等级,例如rank 0 写入 block3.vti,rank 1 写入 block12.vti,等等。在这种情况下,您可以使用 MPI_GATHER 将每个进程的块号收集到 rank 0 的数组中,然后遍历数组的元素。

  • 有的队伍写一个VTK文件,有的不写,而且块顺序不跟随队伍。这与前面的情况类似 - 只是让不写入块的排名发送一个负块号,然后排名 0 将跳过负数组元素。

  • 块编号遵循等级顺序,但并非所有等级都写入块。在这种情况下,您可以使用MPI_GATHER 从每个等级中收集一个LOGICAL 值,以指示它是否已写入块。

【讨论】:

  • 我同意。我最终只是在 0 级上进行循环并重新计算有关所有其他等级的“名称”信息。 pvti 文件不需要知道每个文件来自哪个等级 - 它只需要知道它的大小以及在哪里找到它。
【解决方案3】:

如果你不着急,可以强制不同任务的输出有序:

! Loop over processes in order
DO n = 0,numProcesses-1

  ! Write to file if it is my turn
  IF(nproc == n)THEN 
    ! Write output here
  ENDIF

  ! This call ensures that all processes wait for each other
#ifdef MPI
  CALL MPI_Barrier(mpi_comm_world,ierr)
#endif

ENDDO

此解决方案很简单,但对于非常大的输出效率不高。这似乎不是你的情况。确保在每次写入后刷新输出缓冲区。如果使用此方法,请确保在实施前进行测试,因为并非所有架构都能保证成功。此方法适用于输出大型 NetCDF 文件而无需传递数据。

【讨论】:

  • 这不能保证工作,并且并不总是在,例如,Cray XT 和 XE 系列机器上。至少你还需要一个同花顺,但即便如此,我也很确定顺序是绝对确定的。
  • 您的意思是“不完全确定”。谢谢你的评论。我还没有机会使用 Cray 计算机。此解决方案适用于输出大型 NetCDF 文件,但我会从每个任务中打开/关闭文件以确保顺序。
猜你喜欢
  • 1970-01-01
  • 2011-05-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-07
  • 1970-01-01
相关资源
最近更新 更多