TTT*_*TTT 1 io performance fortran
我正在研究一组严重 I/O 绑定的 Fortran 程序,因此我正在尝试对其进行优化。我在多个 地方读到写整个数组比单个元素WRITE(10)arr快,即比DO i=1,n; WRITE(10) arr(i); ENDDO. 但是,我不清楚我的案子在这方面会落在哪里。从概念上讲,我的代码类似于:
OPEN(10,FILE='testfile',FORM='UNFORMATTED')
DO i=1,n
[calculations to determine m values stored in array arr]
WRITE(10) m
DO j=1,m
WRITE(10) arr(j)
ENDDO
ENDDO
Run Code Online (Sandbox Code Playgroud)
但是m每次DO i=1,n循环都可能发生变化,因此写入整个数组arr不是一种选择。因此,折叠 DO 循环以进行写入最终会得到WRITE(10) arr(1:m),这与写入整个数组不同。这是否仍然可以加快写作速度,那么阅读呢?我可以在计算后分配一个大小为 m 的数组,将值分配给该数组,写入它,然后释放它,但这似乎太复杂了。
我还看到了有关隐含 DO 循环写入的不同信息,即WRITE(10) (arr(j),j=1,m)它们是否有助于/损害 I/O 开销。
我现在正在运行几个测试,并打算更新我的观察结果。其他适用的建议
额外细节:
更新
我用WRITE(10) arr(1:m)和运行代码READ(10) arr(1:m)。我对这些进行了测试,结果显示WRITE代码的运行时间减少了约 30% ,输出文件也略小于原始文件大小的一半。对于第二个代码,读入文件,我让代码基本上什么都不做,只是读取文件来比较纯读取时间。这将运行时间减少了 30 倍。
避免通过循环多个操作来输出数组的目的WRITE()是避免多个WRITE()操作。输出的数据是数组的所有成员并不是特别重要。
通过单个WRITE()操作写入数组部分或整个数组是一个不错的选择。隐式DO循环不可能比显式外循环差,但它是否更好是编译器实现的问题。(尽管我希望隐含的 -DO比外循环更好。)
小智 5
如果您使用普通的无格式(面向记录的)I/O,您还要在数据本身之前和之后写入一个记录标记。因此,您向每个数据项添加了 8 个字节(通常)的开销,如果您的数字是双精度,这可以轻松(几乎)使写入磁盘的数据翻倍。其他答案中提到的运行时开销也很重要。
如果您使用未格式化的流,则上述参数不适用。
所以,使用
WRITE (10) m
WRITE (10) arr(1:m)
Run Code Online (Sandbox Code Playgroud)
对于 gfortran,这比隐式DO循环(即解决方案WRITE (10) (arr(i),i=1,m))更快。
在建议的解决方案中,构建一个数组描述符并通过一次调用将其传递给库。然后可以更有效地完成 I/O,在您的情况下,利用数据是连续的这一事实。
对于隐含DO循环,gfortran问题多库调用,与多更多的开销。这可以优化,并且是长期存在的错误报告PR 35339 的主题,但是一些复杂的极端情况和可行替代方案的存在使其无法优化。
我还建议在流访问中进行 I/O,不是因为节省了相当微不足道的空间(见上文),而是因为在写入时保持领先的记录标记最新需要查找,这是额外的努力。
如果您的数据非常大,超过 ~ 2^31 字节,您可能会遇到记录标记的不同行为。gfortran 在这种情况下使用子记录(与英特尔兼容),但它应该可以正常工作。我不知道波特兰在这种情况下做了什么。
对于读取,当然可以读取 m,然后分配一个可分配的数组,然后在一个READ语句中读取整个数组。
| 归档时间: |
|
| 查看次数: |
955 次 |
| 最近记录: |