tl; dr :我发现在某些情况下,“隐含的”写入比明确的写入慢,并且想要理解为什么/如果我可以改进它。
详情:
我有一个代码可以起到以下作用:
DO i=1,n
calculations...
!m, x, and y all change each pass through the loop
IF(m.GT.1)THEN
DO j=1,m
WRITE(10,*)x(j),y(j) !where 10 is an output file
ENDDO
ENDIF
ENDDO
输出文件最终相当大,所以看起来写作是一个很大的性能因素,所以我想优化它。在任何人要求之前,不,由于各种下游要求,远离ASCII不是一种选择。因此,我将IF
语句(和内容)重写为:
IF(m.GT.1)THEN
!build format statement for write
WRITE(mm1,*)m-1
mm1=ADJUSTL(mm1)
!implied do write statement
WRITE(10,'('//TRIM(mm1)//'(i9,1x,f7.5/),i9,1x,f7.5)')(x(j),y(j),j=1,m)
ELSEIF(m.EQ.1)THEN
WRITE(10,'(i9,1x,f7.5)')x(1),y(1)
ENDIF
这将根据要写出的值的#构建格式语句,然后执行单个write语句来输出内容。我发现使用这个公式代码实际运行速度较慢。作为参考,当要写入的数据量固定时,我在同一系统(硬件和软件)上看到了显着的加速。假设WRITE
语句本身更快,那么这意味着构建该语句的几行的开销会增加时间,但这似乎很难相信。作为参考,m
可能会有相当大的变化,但可能平均至少为1000.字符串//
的串联是一个非常慢的运算符,还是我还缺少其他东西?提前致谢。
答案 0 :(得分:2)
我还没有添加具体的时序信息,但是使用隐含的do循环进行数据传输是不必要的复杂。
在第一个片段中,使用显式循环,您将每对数字写入不同的记录,并希望使用隐含的do循环重复此输出。为此,您可以使用斜杠编辑描述符在写入一对后终止每个记录。
不必要的复杂性来自两个方面:
作为Vladimir F comments,您可以使用非常大的重复计数:当没有更多项目要写入时,处理编辑描述符并不是错误的。当到达这样的非匹配描述符时,输出终止(成功)。那你可以写一下
WRITE(10,'(*(i9,1x,f7.5/))') (x(j),y(j),j=1,m) ! * replacing a large count
而不是if构造和格式创建。
现在,这与您的第一个输出完全匹配。如上所述,当没有相应的项目要输出时,在到达数据编辑描述符时会出现输出终止。这意味着/
将在此之前得到处理:您有一个最终的空记录。
冒号编辑描述符在这里很有用:
WRITE(10,'(*(i9,1x,f7.5,:,/))') (x(j),y(j),j=1,m)
如果没有要处理的剩余输出项,则在达到:
处理时立即停止。
但我的首选方法是更简单的
WRITE(10,'(i9,1x,f7.5)') (x(j),y(j),j=1,m) ! No repeat count
您有更详细的格式来包含记录终止。但是,我们有所谓的格式返回:如果达到格式结束并且还有更多要输出,那么记录将被终止,处理将返回到格式的开头。
这些东西是否能让你的输出更快还有待观察,但它们肯定会使代码本身更清晰,更清晰。
作为最后一点,它曾经很时髦,以避免额外的X
编辑。如果您的数字适合宽度为7的字段,则1x,f7.5
可以替换为f8.5
并具有相同的外观:表示在字段中是右对齐的。据称,这种减少具有性能优势,而且描述符的切换次数更少。