《量化投资:以MATLAB为工具》

MATLAB技术论坛

 找回密码
 注册账号
查看: 8874|回复: 17
收起左侧

[基础] 提高fwrite和fprintf函数的I/O性能

    [复制链接]
发表于 2013-4-30 11:23:40 | 显示全部楼层 |阅读模式
本文翻译于http://undocumentedmatlab.com,内容结构稍有调整,但保留其核心技术,只限于技术交流!

今天我们将讨论下著名的fwrite(fprintf)函数,它们是用来进行二进制(文本)文件写入操作的。由于fwrite函数是底层I/O函数,且使用十分频繁,很多用户会质疑,它怎么可能还有性能提升的空间,要是有MathWorks早就更新了。

Flushing 和 Buffer

不像C/C++语言,在MATLAB中调用fwirte(fprintf)函数时,MATLAB会自动刷新(flush)输出缓存(buffer),这一点MATLAB的帮助文档没有正面直接了当的说明,只是在fopen函数中隐晦的涉及

fopen.jpg

看到这里,很多用户估计应该猜到了该怎么做了。在写入数据的时候,假如没有缓存(buffer),那么每次调用fwrite函数,就需要进行一次文件写入操作,这种方式将严重降低I/O性能!

下面看一组比较数据,首先我们没有使用缓存方式
  1. data = randi(250,1e6,1);  % 生成一组数据,用来测试I/O性能

  2. % 标准形式,没有应用缓存输出 - 慢
  3. fid = fopen('demo.dat', 'wb'); % w是小写,b表示二进制
  4. tic, for idx = 1:length(data), fwrite(fid,data(idx)); end, toc
  5. fclose(fid);

  6. Elapsed time is 14.983201 seconds.
复制代码
消耗了大概15s,下面看看使用缓存的方式
  1. % 缓存输出模式 – 快3倍
  2. fid = fopen('demo.dat', 'Wb'); % 注意W是大写,b表示二进制
  3. tic, for idx = 1:length(data), fwrite(fid,data(idx)); end, toc
  4. fclose(fid);

  5. Elapsed time is 5.616357 seconds.
复制代码
使用缓存后时间缩短至5.6s,看来效率提高了不少呀!

我们无法理解MathWorks为什么将fopen默认设置为非缓存模式,但也许有他们的理由吧!不过当您在写大型数据文件的时候,推荐还是使用缓存模式('w')吧!

Chunking I/O

使用缓存进行写操作,其实就是为了减少数据文件的访问次数,因此在MATLAB中,假如先将所有的数据都准备好,然后一次性调用fwrite函数将其写入文件中
  1. fid = fopen('demo.dat', 'wb'); % 注意是小写w
  2. tic, fwrite(fid,data); toc
  3. fclose(fid);

  4. Elapsed time is 0.034816 seconds.
复制代码
可以看出即使是非缓存模式,写入30ms的效率还是很高的。

但是假如我们读写的是网络文件,由于网络原因可能需要较长的时间,此时将大数据拆开成很多小块,然后分块处理是一个明智的选择。
  1. h = waitbar(0, 'Saving data...', 'Name','Saving data...');
  2. cN = 100;  % number of steps/chunks

  3. % Divide the data into chunks (last chunk is smaller than the rest)
  4. dN = length(data);
  5. dataIdx = [1 : round(dN/cN) : dN, dN+1];  % cN+1 chunk location indexes

  6. % Save the data
  7. fid = fopen('test.dat', 'Wb');
  8. for chunkIdx = 0 : cN-1
  9.    % Update the progress bar
  10.    fraction = chunkIdx/cN;
  11.    msg = sprintf('Saving data... (%d%% done)', round(100*fraction));
  12.    waitbar(fraction, h, msg);

  13.    % Save the next data chunk
  14.    chunkData = data(dataIdx(chunkIdx+1) : dataIdx(chunkIdx+2)-1);
  15.    fwrite(fid,chunkData);
  16. end

  17. fclose(fid);
  18. close(h);
复制代码
总的来说,本文中的技术同时适用于fprintf和fwrite函数,但是存储和读取二进制文件(fwrite/fread)远远快于文本文件(fprintf/fscanf/textscan),因此如果数据不是为了人为可读,尽量使用二进制保存!
发表于 2018-6-30 03:58:40 | 显示全部楼层

Nike Boston Celtics Authentic Jerseys

Jets defensive back Antonio Allen left in the second quarter with a head injury,Cheap NHL Jerseys Authentic. The safety was starting at cornerback because of injuries to the secondary,NBA Jerseys Store. Allen and teammate Demario Davis banged helmets after a 7-yard catch by Jennings,Jae Crowder Jersey.
EAST RUTHERFORD,Jerseys Soccer Authentic, N.J. (AP) — New York Giants left guard Geoff Schwartz has been carted off the field after dislocating his toe late in the second quarter against the Jets.
Jets linebacker Troy Davis (leg) and Giants wide receiver Marcus Harris (shoulder) and cornerback Zack Bowman (bruised triceps) also left and will not return,World Baseball Classic Jerseys 2017.
Schwartz went down after an incomplete pass to Rashad Jennings on Friday night. Trainers immediately came out and examined his right foot,Marlon Humphrey Jersey, and Schwartz grimaced in pain. A cart was called and he was brought to the locker room.
回复 支持 反对

使用道具 举报

发表于 2017-6-22 22:01:06 | 显示全部楼层
看帖回帖是种美德。
回复 支持 反对

使用道具 举报

发表于 2013-4-30 12:22:07 | 显示全部楼层
原来还可以这样。学习了。
回复 支持 反对

使用道具 举报

发表于 2013-4-30 15:20:43 | 显示全部楼层
不错
回复 支持 反对

使用道具 举报

发表于 2013-4-30 18:21:56 | 显示全部楼层
回复 支持 反对

使用道具 举报

发表于 2013-4-30 20:22:45 | 显示全部楼层
很是有用,受益匪浅
回复 支持 反对

使用道具 举报

发表于 2013-5-1 10:40:48 | 显示全部楼层
回复 支持 反对

使用道具 举报

发表于 2013-5-2 19:20:35 | 显示全部楼层
学习了,谢谢版主无私分享
回复 支持 反对

使用道具 举报

发表于 2013-5-2 20:07:44 | 显示全部楼层
回复 支持 反对

使用道具 举报

发表于 2013-5-2 20:20:26 | 显示全部楼层
学习啦,受益匪浅
回复 支持 反对

使用道具 举报

发表于 2013-5-12 15:38:03 | 显示全部楼层
赞,太有用了,非常感谢!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册账号

本版积分规则

QQ|网站地图|MATLAB技术论坛|Simulink仿真论坛 ( 蜀ICP备19014457号 

GMT+8, 2020-2-23 12:35 , Processed in 0.122779 second(s), 30 queries , Gzip On.

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

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