下面是nim中的一个测试,它显示fwrite引入了函数调用开销,并且您端的批处理减少了时钟时间。 当batchPow从0增加到10时,时钟时间从36秒减少到4秒nim r -d:case1 -d:danger --gc:arc main.nim | wc -l 36秒 nim r -d:case2 -d:danger --gc:arc -d:batchPow:10 main.nim | wc -l 4秒 即使LTO也不能帮助fwrite的函数调用开销,正如您在-d:case1 --passc:-flto --passl:-flto中看到的那样
var buf: string
let n = 1000_000_000
for i in 0..<n:
let c = cast[char](i)
when defined case1: # 36 seconds
stdout.write c
when defined case2: # 4 seconds
const batchPow {.intdefine.} = 10
buf.add c
if ((i and (2 shl batchPow - 1)) == 0) or (i == n-1):
stdout.write buf
buf.setLen 0
//open and init
char mybuffer [1024];
std::ofstream filestr("yourfile");
filestr.rdbuf()->pubsetbuf(mybuffer,1024);
// write your data
filestr.write(data,datasize);
8条答案
按热度按时间wd2eg0qa1#
首先,
fwrite()
是一个库,而不是一个系统调用。其次,它已经缓冲了数据。您可能需要尝试增加缓冲区的大小。这是通过使用
setvbuf()
来完成的。在我的系统上,这只有一点点帮助,但YMMV。如果
setvbuf()
不起作用,您可以自己进行缓冲,只有在积累了足够的数据后才调用fwrite()
。这涉及到更多的工作,但几乎肯定会加快编写速度,因为您自己的缓冲可以做得比fwrite()
的更轻量级。**edit:**如果有人告诉您问题出在
fwrite()
调用的数量上,请要求查看证据。更好的办法是,自己进行性能测试。在我的计算机上,使用fwrite()
写入500,000,000个双字节需要11秒。这相当于大约90 MB/s的吞吐量。最后但并非最不重要的是,我的测试中的11秒与您的问题中提到的1小时之间的巨大差异暗示了代码中可能存在其他原因导致了非常差的性能。
v7pvogib2#
你的问题不是
fwrite()
的缓冲,而是用少量数据调用库的总开销。如果您只写入1MB数据,则要进行250000次函数调用。你最好尝试在内存中收集你的数据,然后用一个单一的调用fwrite()
写入磁盘。更新:如果需要证据:
字符串
dphi5xsq3#
好吧,那很有趣。我想我应该写一些实际的代码来看看速度是多少。这就是了使用C++ DevStudio 2010 Express编译。这里有很多代码。它乘以5种数据写入方式:
请检查我没有做任何一个以上的愚蠢的事情。
该程序使用QueryPerformanceCounter来计时代码,并在关闭文件后结束计时,尝试包括任何挂起的内部缓冲数据。
在我的机器上的结果(一个旧的WinXP SP3盒子):-
您可能会得到不同的结果,具体取决于您的设置。
请随意编辑和改进代码。
字符串
ghhkc1vu4#
如果你只从一个线程写入,请尝试使用
fwrite_unlocked
。在这种情况下,相对于直fwrite
来说,它确实是奇迹。uqcuzwp85#
首先也是最重要的:小的fwrites()* 慢,因为每个fwrites都要测试其参数的有效性,做等价于flockfile()的操作,可能是fflush(),追加数据,返回success:这个开销加起来--不像对write(2)的微小调用那么多,但它仍然很明显。
证明:
字符串
话虽如此,你可以做许多评论者建议的,即在fwrite之前添加自己的缓冲:这是非常简单代码,但您应该测试它是否真的给您带来了任何好处。
如果你不想自己滚动,你可以使用skalibs中的buffer接口,但是你可能会花更长的时间来阅读文档,而不是自己写。
pqwbnv8z6#
stdio中FILE * 层的意义在于它为您完成了缓冲。这可以节省系统调用开销。正如其他人所指出的,有一件事可能仍然是一个问题,那就是库调用开销,这个开销要小得多。另一件可能会困扰你的事情是同时写入磁盘上的许多不同位置。(磁盘旋转,磁头大约需要8毫秒才能到达正确的位置进行随机写入。)
如果您确定库调用开销是问题所在,我建议您使用vector滚动您自己的琐碎缓冲,并定期将vector刷新到文件中。
如果问题是有大量的写操作分散在磁盘上,请尝试使用setvbuf()提升缓冲区大小。如果可以的话,尝试每个文件4MB左右的数字。
rryofs0p7#
下面是
nim
中的一个测试,它显示fwrite
引入了函数调用开销,并且您端的批处理减少了时钟时间。当
batchPow
从0增加到10时,时钟时间从36秒减少到4秒nim r -d:case1 -d:danger --gc:arc main.nim | wc -l
36秒nim r -d:case2 -d:danger --gc:arc -d:batchPow:10 main.nim | wc -l
4秒即使LTO也不能帮助fwrite的函数调用开销,正如您在
-d:case1 --passc:-flto --passl:-flto
中看到的那样字符串
bis0qfac8#
应该很容易滚动自己的缓冲区。但幸运的是,标准的C++有你想要的东西。使用std::ofstream:
字符串
**编辑:**错误,使用ofstream而不是fstream,因为它不清楚从标准切换缓冲区是输入还是输出?)