找回密码
 注册
关于网站域名变更的通知
查看: 416|回复: 1
打印 上一主题 下一主题

在MATLAB中如何提高fwrite和fprintf函数的I/O性能

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2020-2-12 09:13 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
% |: g2 B$ p; R* a# e5 ~5 @9 O$ n; d
今天我们将讨论下著名的fwrite(fprintf)函数,它们是用来进行二进制(文本)文件写入操作的。由于fwrite函数是底层I/O函数,且使用十分频繁,很多用户会质疑,它怎么可能还有性能提升的空间,要是有MathWorks早就更新了。
* S  ]: O9 s; v. p" k: Y
5 ]2 l( l( I  _5 mFlushing 和 Buffer
; L1 z, T, K3 ?0 q
* N; s) \# e! J/ F0 @9 |不像C/C++语言,在MATLAB中调用fwirte(fprintf)函数时,MATLAB会自动刷新(flush)输出缓存(buffer),这一点MATLAB的帮助文档没有正面直接了当的说明,只是在fopen函数中隐晦的涉及; l. L; o/ g1 W% C2 h  z, J/ o6 P

* k1 ^/ f. _, H* ~5 Z; w7 `. t
$ D0 g8 ]! E0 J( z: e& W1 L
: P2 m" \. G8 T看到这里,很多用户估计应该猜到了该怎么做了。在写入数据的时候,假如没有缓存(buffer),那么每次调用fwrite函数,就需要进行一次文件写入操作,这种方式将严重降低I/O性能!
( [0 n6 W) e2 d
+ w- f. u" C/ G; T下面看一组比较数据,首先我们没有使用缓存方式
# E: d9 ^, n; M6 q. d+ O* u
  • data = randi(250,1e6,1);  % 生成一组数据,用来测试I/O性能
  • % 标准形式,没有应用缓存输出 - 慢
  • fid = fopen('demo.dat', 'wb'); % w是小写,b表示二进制
  • tic, for idx = 1:length(data), fwrite(fid,data(idx)); end, toc
  • fclose(fid);
  • Elapsed time is 14.983201 seconds.
    9 L! v7 w# D+ z$ b
/ h2 r: K$ D" Y+ `, V; O, o8 C8 M. E

; I/ {- Y% N( v# q0 x8 d. {2 b消耗了大概15s,下面看看使用缓存的方式
7 m* ]" I. v5 u1 c
! c- ]1 @. ^' L/ E7 }. W
  • % 缓存输出模式 – 快3倍
  • fid = fopen('demo.dat', 'Wb'); % 注意W是大写,b表示二进制
  • tic, for idx = 1:length(data), fwrite(fid,data(idx)); end, toc
  • fclose(fid);
  • Elapsed time is 5.616357 seconds.
    8 m+ Y8 J0 s2 U2 n5 ~) n0 T# Y

0 d5 Z; ?# ]3 W+ ~0 f- x$ K
/ W3 m  N# z' t( z# M使用缓存后时间缩短至5.6s,看来效率提高了不少呀!5 ]1 F2 E8 E. n# C/ @4 Y
4 G; E8 c7 b/ P
我们无法理解MathWorks为什么将fopen默认设置为非缓存模式,但也许有他们的理由吧!不过当您在写大型数据文件的时候,推荐还是使用缓存模式('w')吧!
2 z! U3 Y+ K* P( ?8 B( J3 k
7 W4 E, y# }+ Z& OChunking I/O
/ c4 J, F+ i, h7 c6 S3 W
9 E, t7 M. L, g& o0 }. _使用缓存进行写操作,其实就是为了减少数据文件的访问次数,因此在MATLAB中,假如先将所有的数据都准备好,然后一次性调用fwrite函数将其写入文件中
, C$ J# @$ S1 d! C- V- y
0 c1 P8 M/ O) s' Q% T
  • fid = fopen('demo.dat', 'wb'); % 注意是小写w
  • tic, fwrite(fid,data); toc
  • fclose(fid);
  • Elapsed time is 0.034816 seconds.1 f& V" G- `  E3 N8 ~1 u3 M

/ Z$ X* U8 A" d
. N) v3 ~- c7 J9 |# T) w可以看出即使是非缓存模式,写入30ms的效率还是很高的。, W2 w7 a3 G% B2 J

; j) J$ @- Z* H% b3 l! g$ V, M但是假如我们读写的是网络文件,由于网络原因可能需要较长的时间,此时将大数据拆开成很多小块,然后分块处理是一个明智的选择。: |, I5 e- F' r! U% A$ t
: F# s& h5 I3 v; ]% o
  • h = waitbar(0, 'Saving data...', 'Name','Saving data...');
  • cN = 100;  % number of steps/chunks
  • % Divide the data into chunks (last chunk is smaller than the rest)
  • dN = length(data);
  • dataIdx = [1 : round(dN/cN) : dN, dN+1];  % cN+1 chunk location indexes
  • % Save the data
  • fid = fopen('test.dat', 'Wb');
  • for chunkIdx = 0 : cN-1
  •   % Update the progress bar
  •   fraction = chunkIdx/cN;
  •   msg = sprintf('Saving data... (%d%% done)', round(100*fraction));
  •   waitbar(fraction, h, msg);
  •   % Save the next data chunk
  •   chunkData = data(dataIdx(chunkIdx+1) : dataIdx(chunkIdx+2)-1);
  •   fwrite(fid,chunkData);
  • end
  • fclose(fid);
  • close(h);
      p, L) z) N7 u, A2 S) A3 S

9 [( c8 L- I# _# I; l. u" x! g8 _
, i' Z& F! f1 o. k2 K总的来说,本文中的技术同时适用于fprintf和fwrite函数,但是存储和读取二进制文件(fwrite/fread)远远快于文本文件(fprintf/fscanf/textscan),因此如果数据不是为了人为可读,尽量使用二进制保存!8 Y& F: u0 H2 o5 {# _- {

- j4 t+ S8 [3 c: M# R* n) ]* [; K! o- t# Z

该用户从未签到

2#
发表于 2020-2-12 19:47 | 只看该作者
在MATLAB中如何提高fwrite和fprintf函数的I/O性能
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-6-11 14:39 , Processed in 0.078125 second(s), 26 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表