freopen stdout 真的更快?
freopen stdout 真的更快?
在一次数独作业中,我发现大部分同学提交的代码中都使用 freopen 来将 stdout 重新指向目标文件进行文件输出操作。我感到十分好奇,关于 freopen 我几乎从未用过,也很少在其它地方看到别人使用,也就是说至少我的认知里该函数不是个常用函数。再来点数据支持:
- 关于
fopen在 Google 中的搜索结果有636万条

- 关于
freopen在 Google 中的搜索结果有35.7万条,少了一个数量级!

所以我想同学们是不是从哪里道听途说了这种用法的好处,或者在某些环境下先入为主而习惯使用 freopen 。我尝试在班级群中发出疑问,果然两个原因都有:
助教 L 说:
我看部分同学的说法是:非常快
能够把文件输出的速度提升到极致
同学 H 说:
以前我记得做c++作业的时候,有这样的,然后我不懂怎么弄,大神就教我可以这样输出到文件,至于为什么。。。我去他宿舍问一下
同学 C 说:
。。。noip都用freopen
关于习惯问题,这里不做展开。只是简单提一下,freopen 重定向 stdout 会让一个普通程序的输出变得麻烦,比如同时读写若干个文件,同时要输出到 console 等。
关于性能问题,这个道听途说就十分不妥,都是做技术的,这样的小问题很容易动手验证,那我们就干一小票试试。
测试环境:Windows 10 / Visual Studio 2015
- 首先,来个函数,对一个连续写入操作计时:
clock_t do_write(FILE* fp, char* data, size_t len) {
// The clock() function returns an approximation of processor time used by the program.
// The value returned is the CPU time used so far as a clock_t;
// to get the number of seconds used, divide by CLOCKS_PER_SEC.
clock_t clock_begin, clock_end;
clock_begin = clock();
for (int i = 0; i < 1000; ++i) {
auto n = fwrite(data, len, 1, fp);
assert(n == 1);
}
fflush(fp);
clock_end = clock();
return clock_end - clock_begin;
}
关于 clock 计时请看以上代码注释
- 然后我们分别以
freopen,fopen打开文件,并且写入 1000MB 看看并输出耗时:
int main() {
auto data = new char[1048576]; // 1MB
// initialize the buffer
for (int i = 0; i < 1048576; ++i)
data[i] = i;
clock_t elapsed;
auto fp_reopen = freopen("data_freopen.bin", "wb", stdout);
assert(fp_reopen != nullptr);
elapsed = do_write(fp_reopen, data, 1048576);
// redirect stdout to console
#ifdef _WIN32
freopen("CONOUT$", "w", stdout);
#else
freopen("/dev/tty", "w", stdout);
#endif
printf("write with freopen clocks elapsed: %zu\n", elapsed);
auto fp = fopen("data_fopen.bin", "wb");
assert(fp != nullptr);
elapsed = do_write(fp, data, 1048576);
fclose(fp);
printf("write with fopen clocks elapsed: %zu\n", elapsed);
delete[] data;
}
测试输出:
write with freopen clocks elapsed: 1644
write with fopen clocks elapsed: 8855
好家伙,果然快很多!但是!为!什!么!?
难道是两种方式打开文件的缓存机制不同?
- 那行,让它们使用同样的缓存:
setvbuf 可以办到!如果不了解,请看这里:http://en.cppreference.com/w/c/io/setvbuf
auto cache = new char[512 * 1024];
auto fp_reopen = freopen("data_freopen.bin", "wb", stdout);
assert(fp_reopen != nullptr);
setvbuf(fp_reopen, cache, _IOFBF, 512 * 1024);
...
auto fp = fopen("data_fopen.bin", "wb");
assert(fp != nullptr);
setvbuf(fp, cache, _IOFBF, 512 * 1024);
...
}
测试输出:
write with freopen clocks elapsed: 1761
write with fopen clocks elapsed: 9146
依!然!如!此!呆坐中。。。
- 连续写入大量数据
- 设置相同的缓存机制
还能有什么影响呢?
- runtime library
- 操作系统
- 文件系统
- 磁盘硬件
想想我们拷贝大文件的现象,一般都是起步很快,然后会下降到一个较稳定的值上下徘徊,这个原因比较明显,系统及硬件都提供了一定的缓存。
- 刚开始缓存空闲,数据都飞快写入缓存
- 同时缓存也不停地在刷入磁盘
- 因为连续写入大量数据,磁盘本身很慢,缓存逐渐被填满,这时候写入缓存也需要等待(现象就是写入速度下降到刷磁盘的速度)
那行了,我们测试是写2个文件,一个先一个后,并且是连续操作,也就是说先写的文件优先享受了缓存带来的好处,后写的文件没有了这个优势。思考完,做个验证:
// 先测 fopen
auto fp = fopen("data_fopen.bin", "wb");
assert(fp != nullptr);
setvbuf(fp, cache, _IOFBF, 512 * 1024);
elapsed = do_write(fp, data, 1048576);
fclose(fp);
printf("write with fopen clocks elapsed: %zu\n", elapsed);
// 再测 freopen
auto fp_reopen = freopen("data_freopen.bin", "wb", stdout);
assert(fp_reopen != nullptr);
setvbuf(fp_reopen, cache, _IOFBF, 512 * 1024);
elapsed = do_write(fp_reopen, data, 1048576);
// redirect stdout to console
#ifdef _WIN32
freopen("CONOUT$", "w", stdout);
#else
freopen("/dev/tty", "w", stdout);
#endif
printf("write with freopen clocks elapsed: %zu\n", elapsed);
测试输出:
write with fopen clocks elapsed: 1561
write with freopen clocks elapsed: 9267
哈哈!答案揭晓! freopen stdout 并没有性能上的优势!
- 进一步做验证,我们依然按照
freopen,fopen的顺序来测试,但是在两次测试中间加上sleep让缓存能空闲出来。这里就不贴代码了,直接上结果:
write with freopen clocks elapsed: 2326
write with fopen clocks elapsed: 2519
结论
要动手验证!验证!验证!而不是道听途说!
Linux也做过测试,结论也一样!
参考
刘未鹏 - 遇到问题为什么应该自己动手
freopen stdout 真的更快?的更多相关文章
- 精通Web Analytics 2.0 (9) 第七章:失败更快:爆发测试与实验的能量
精通Web Analytics 2.0 : 用户中心科学与在线统计艺术 第七章:失败更快:爆发测试与实验的能量 欢迎来到实验和测试这个棒极了的世界! 如果Web拥有一个超越所有其他渠道的巨大优势,它就 ...
- mysql DB server端,如何让读写更快
其实,我不是专业的DB管理同学,甚至算不上会了解.只是在最近的工作中,遇到了DB server端优化的契机,所以把这些手段记录下来: 通过调整这个参数的值,可以让DB更给力: 这两个参数的含义: 1. ...
- 利用1.1.1.1进行DNS网络加速,仅需2分钟让网络更快
NEWS 近日,Cloudflare 和 APNIC联合推出了1.1.1.1DNS网络加速. Cloudflare 运行全球规模最大.速度最快的网络之一.APNIC 是一个非营利组织,管理着亚太和大洋 ...
- 让Python代码更快运行的 5 种方法
不论什么语言,我们都需要注意性能优化问题,提高执行效率.选择了脚本语言就要忍受其速度,这句话在某种程度上说明了Python作为脚本语言的不足之处,那就是执行效率和性能不够亮.尽管Python从未如C和 ...
- 比Python、Java更快的 Go 语言,能否称霸江湖?
关注之后加星标,江湖要事早知道 文章来源:jb51.net 有一种语言堪称比语言排行榜前五热门选手的Python.Java更快,它就是GO语言. Go于2009年11月正式宣布推出,成为开放源代码 ...
- linux 下程序员专用搜索源码用来替代grep的软件ack(后来发现一个更快的: ag), 且有vim插件的
发现一个比ack更快更好用的: https://github.com/ggreer/the_silver_searcher , 使用时命令为ag,它是基于ack的代码二次开发的,所有使用方法基本 ...
- 11个点让你的Spring Boot启动更快
前言 使用的是 OpenJDK 11. java --version openjdk 11.0.1 2018-10-16 OpenJDK Runtime Environment 18.9 (build ...
- 假如 UNION ALL 里面的子句 有 JOIN ,那个执行更快呢
比如: select id, name from table1 where name = 'x' union all select id, name from table2 where name = ...
- 【译】更快的方式实现PHP数组去重
原文:Faster Alternative to PHP’s Array Unique Function 概述 使用PHP的array_unique()函数允许你传递一个数组,然后移除重复的值,返回一 ...
随机推荐
- linux添加磁盘空间
首先你要关掉系统,把分配的硬盘空间变大,或者重新建立一个虚拟硬盘(这时下面的就不是sda了,而是sdb1了).这两种方法都可行,我都试过了.其次用root用户登录到你的linux系统,查看你系统的分区 ...
- 死磕nginx系列-nginx日志配置
nginx access日志配置 access_log日志配置 access_log用来定义日志级别,日志位置.语法如下: 日志级别: debug > info > notice > ...
- 对比flash与ajax哪个好?
Ajax的优势: (1)可搜索性 普通的文本网页会更有利于SEO.文本内容是搜索引擎容易检索的,而繁琐的swf字节码却是搜索引擎不愿触及的.虽然Google等一些大型的搜索引擎可以检索SWF内部的内容 ...
- Docker技术入门与实战 第二版-学习笔记-7-数据管理(volume)
Docker 数据管理 为什么要进行数据管理呢?因为当我们在使用container时,可能会在里面创建一些数据或文件,但是当我们停掉或删除这个容器时,这些数据或文件也会同样被删除,这是我们并不想看见的 ...
- Android4.4 ContentResolver查询图片无效 及 图库删除 增加图片后,ContentResolver不更新的问题解决
问题背景: 参考链接 做了一个图片浏览,用ContentResolver扫描图库照片,且严格按照时间拍摄顺序排好序显示在listview里.如下图所示: 遇到的问题是在4.2的手机上能正常显示,但是新 ...
- LFS 8.3 中文翻译版本发布!
导读 很多同学都已经学习了 Linux ,可能已经在自己的机器上安装过 Linux,甚至都能搭建个简单的个人博客,也有可能编译部署过邮件服务器之类的软件,可是感觉仍然对 Linux 有点摸不着,颇有隔 ...
- UPF Usage
在 multi-voltage design 中,当涉及到多个power supply 时,需要 upf 文件来描述power细节,现将 upf 中的基本概念和使用方法记录如下: upf 中的基本概念 ...
- 突然的明白--public static 类名 函数名()
public static ImageUtilEngine getImageEngine() { return imageEngine; } 这个是什么啊........纠结了一个多星期的东西 忽然间 ...
- Debian 鼠标左右手
环境:debian testing;xfce4桌面 在debian中想把鼠标改为左手操作,在设置中调整鼠标的按钮为左撇子根本没用!网上搜索后发现事实很简单,简单到不知该怎么说. 废话少说,放码过来. ...
- 反向路径过滤——reverse path filter
原文地址:反向路径过滤——reverse path filter 作者:pwp_cu 反向路径过滤——reverse path filter 一.原理先介绍个非对称路由的概念参考<Underst ...