C++ 读取大量ASCII数字并以二进制形式写入
我有大约1.5 Gb的浮点数的数据文件,存储为ASCII文本,用空格分隔,例如,C++ 读取大量ASCII数字并以二进制形式写入,c++,optimization,data-processing,C++,Optimization,Data Processing,我有大约1.5 Gb的浮点数的数据文件,存储为ASCII文本,用空格分隔,例如,1.2334 2.3456 3.4567等等 在处理这些数字之前,我首先将原始文件转换为二进制格式。这是很有帮助的,因为我可以选择是使用float还是double,减少文件大小(对于double文件大小约为800 MB,对于float文件大小约为400 MB),并在处理数据后读取适当大小的数据块 我编写了以下函数以将ASCII转换为二进制: template<typename RealType=float>
1.2334 2.3456 3.4567
等等
在处理这些数字之前,我首先将原始文件转换为二进制格式。这是很有帮助的,因为我可以选择是使用float
还是double
,减少文件大小(对于double
文件大小约为800 MB,对于float
文件大小约为400 MB),并在处理数据后读取适当大小的数据块
我编写了以下函数以将ASCII转换为二进制:
template<typename RealType=float>
void ascii_to_binary(const std::string& fsrc, const std::string& fdst){
RealType value;
std::fstream src(fsrc.c_str(), std::fstream::in | std::fstream::binary);
std::fstream dst(fdst.c_str(), std::fstream::out | std::fstream::binary);
while(src >> value){
dst.write((char*)&value, sizeof(RealType));
}
// RAII closes both files
}
但它似乎没有写入数据!我正在处理它…使用RealType
的std::vector
将写操作聚合到固定的缓冲区中。您的逻辑应该是这样的:
std::vector
写调用,从而减少复制和缓冲逻辑。我做了完全相同的事情,只是我的字段由制表符'\t'
分隔,并且我还必须处理每行末尾的非数字注释和散布数据的标题行
是我的实用程序的文档
我也有速度问题。以下是我为将性能提高约20倍所做的工作:
- 用内存映射文件替换显式文件读取。同时绘制两个街区的地图。当处理完一条直线后位于第二个块中时,请与第二个和第三个块重新映射。这样,跨越块边界的线在内存中仍然是连续的。(假设没有一条线大于一个块,您可能可以增加块大小来保证这一点。)
- 使用SIMD指令,如
\u mm\u cmpeq\u epi8
搜索行尾或其他分隔符。在我的例子中,任何包含'='
字符的行都是需要不同处理的元数据行
- 使用一个基本的数字解析函数(我使用了一个自定义函数来解析HH:MM:SS格式的时间,
strtod
和strtol
非常适合抓取普通数字)。这些函数比istream
格式化的提取函数快得多
< L>使用OS文件写API代替标准C++ API。< /LI>
如果你想在300000线/秒范围内实现吞吐量,那么你应该考虑类似的方法。< /P>
当你不使用C++标准流时,你的可执行文件也会缩小。我有205KB,包括一个图形界面,并且只依赖于Windows附带的dll(不需要MSVCRTxx.dll)。再看一遍,我仍然在用C++流进行状态报告。< /P>你是说把文件大小缩小到800兆字节而不是800 GB?我想你会发现使用经典的C<代码>文件和<代码> fSCANFF()/Cuff>比使用<代码> FStuts有点快。也不要认为你应该在你的输入文件上使用 fSt::Boo2/<代码>它可能对性能没有任何影响,但是正确性会受到影响。@ DanF -是的。谢谢。性能受到你使用的操作系统的极大影响。C++是好的,除了性能外,没有打败OS的API。您可以在读取文件时使用异步文件访问进行处理。注意:您编辑的文章(包括64K写入缓冲区)应使用k*sizeof(RealType)
作为写入大小(以字节为单位),而不是buffer.size()
,后者是类型RealType
的元素计数。此外,dst.flush();dst.close();
应该在退出时完成。使用std::vector
没有任何好处,因为它是一个固定大小的数组。顺便说一句,只是有理由处理一个文件。结果:在55.244秒内完成了2508MB的处理(吞吐量:534426行/秒)
。如果同时包含源和目标,则为3.87GB的磁盘I/O。
template<typename RealType=float>
void ascii_to_binary(const std::string& fsrc, const std::string& fdst{
std::vector<RealType> buffer;
typedef typename std::vector<RealType>::iterator VectorIterator;
buffer.reserve(65536);
std::fstream src(fsrc, std::fstream::in | std::fstream::binary);
std::fstream dst(fdst, std::fstream::out | std::fstream::binary);
while(true){
size_t k = 0;
while(k<65536 && src >> buffer[k]) k++;
dst.write((char*)&buffer[0], buffer.size());
if(k<65536){
break;
}
}
}