我试图在控制台屏幕上打印一些长迭代的进度指标。 具体来说,我想要这样的东西显示在控制台屏幕上:
----|----|----|----|
这是打印-
每次迭代后(不是5的倍数),并打印|
每5次迭代之后。 这应该是实时发生的:每次迭代一个字符。
我试着用ADVANCE='NO'
选项来使用WRITE
语句,但是所有的程序执行后,或者在使用另一个带有ADVANCE='YES'
选项的WRITE
语句后,所需的输出只显示在屏幕上。
这是我的代码:
PROGRAM TEST IMPLICIT NONE INTEGER :: i DO i = 1,20 CALL SLEEP(2) IF (MOD(i,5).EQ.0) THEN WRITE(*,'(A)',ADVANCE='NO'), '|' ELSE WRITE(*,'(A)',ADVANCE='NO'), '-' END IF END DO END PROGRAM TEST
我使用SLEEP
子程序来模拟每个迭代需要很多时间的事实。
flush语句可以用来表示写入文件的数据是“可用的”。 这种说法意味着依然依赖于处理器,但是通常情况下,你会得到你想要的问题的行为。
flush语句需要一个单元号。 要输出到控制台,您可以使用ISO_FORTRAN_ENV中的OUTPUT_UNIT。 英特尔Fortran 17.0和更低版本应该显示您想要的行为,对于当前的ifort beta,您还需要在写入语句中使用OUTPUT_UNIT(这可能是编译器/编译器运行时错误)。
(您还应该修复WRITE语句中的语法错误。)
诚然,你的设置应该在理论上工作(考虑到不同编译器的不同行为等)。 上面使用FLUSH(索引)语句的建议,使用与标准输出相关的索引,甚至可以解决不同编译器之间的差异。 但是,在某些环境(更具体地说是集群和HPC超级计算机)中,这仍然不能解决您的问题。 当我自己实施一个进度条的时候,我碰到了同样的问题,使我得出以下结论:
HPC系统可能会在输出前执行大量数据缓冲,以提高机器的效率(磁盘写入是最慢的内存访问选项),因此有时可能会取消我们的刷新命令。 进度条在实际完成之前反过来将不会显示出太多的进展,此时整个酒吧将被立即显示。 有些选项可以强制基础架构不使用这种缓冲(一般系统管理员不会理解这一点),例如通过设置编译器标志-assume nobuffered_stdout 。 因此,HPC应用程序的最佳解决方案是构建稍微修改的进度条,其中不使用回车符。
您可以通过在桌面上运行相同的代码来轻松测试,FLUSH语句将为您提供预期的行为。
继IanH和DannyVanpoucke关于flush语句的建议之后,这是一个按预期工作的代码版本:
PROGRAM TEST IMPLICIT NONE INTEGER :: i DO i = 1,20 CALL SLEEP(2) IF (MOD(i,5).EQ.0) THEN WRITE(UNIT=6,FMT='(A)',ADVANCE='NO'), '|' FLUSH(UNIT=6) ELSE WRITE(UNIT=6,FMT='(A)',ADVANCE='NO'), '-' FLUSH(UNIT=6) END IF END DO END PROGRAM TEST
正如下面的一些问题所指出的那样,似乎需要使用flush语句来使缓冲区中的信息可用,这是英特尔Fortran特定的问题。