1

我有大约 1.5 Gb 的浮点数的数据文件,它们存储为 ASCII 文本,由空格分隔,例如,1.2334 2.3456 3.4567等等。

在处理这些数字之前,我首先将原始文件转换为二进制格式。这很有帮助,因为我可以选择是否使用floatdouble,减小文件大小(大约 800 MBdouble和 400 MB float),并在处理数据后读取适当大小的块。

我编写了以下函数来进行 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
}

我想加快速度acii_to_binary,但我似乎无法提出任何建议。我尝试以 8192 字节的块读取文件,然后尝试在另一个子例程中处理缓冲区。这似乎很复杂,因为缓冲区中的最后几个字符可能是空格(在这种情况下一切都很好),或者是一个截断的数字(这非常糟糕)——处理可能的截断的逻辑似乎不值得。

你会怎么做来加速这个功能?我宁愿依赖标准 C++(C++11 也可以),没有额外的依赖,比如 boost。

谢谢你。

编辑:

@大卫施瓦茨:

我尝试按如下方式实施您的建议:

 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;
      }
    }
  }

但它似乎没有写入数据!我在做这个工作...

4

2 回答 2

3

我做了完全相同的事情,除了我的字段由制表符分隔,'\t'而且我还必须处理每行末尾的非数字注释和穿插数据的标题行。

是我的实用程序的文档。

我也遇到了速度问题。以下是我为将性能提高约 20 倍所做的事情:

  • 用内存映射文件替换显式文件读取。一次映射两个块。当您在处理完一行后处于第二个块中时,与第二个和第三个块重新映射。这样,跨越块边界的线在内存中仍然是连续的。(假设没有一行大于一个块,您可能可以增加块大小来保证这一点。)
  • 使用 SIMD 指令,例如_mm_cmpeq_epi8搜索行尾或其他分隔符。就我而言,任何包含'='字符的行都是需要不同处理的元数据行。
  • 使用准系统数字解析功能(我使用自定义功能来解析 HH:MM:SS 格式的时间,strtod非常strtol适合抓取普通数字)。istream这些比格式化的提取函数快得多。
  • 使用 OS 文件写入 API 而不是标准 C++ API。

如果您梦想吞吐量在 300,000 行/秒范围内,那么您应该考虑采用类似的方法。

当您不使用 C++ 标准流时,您的可执行文件也会缩小。我有 205KB,包括一个图形界面,并且只依赖于 Windows 附带的 DLL(不需要 MSVCRTxx.dll)。再看一遍,我仍在使用 C++ 流进行状态报告。

于 2013-02-07T21:43:40.210 回答
0

使用 a of将写入聚合到固定缓冲区中。你的逻辑应该是这样的:std::vectorRealType

  1. 为 a 分配std::vector<RealType>65,536 个默认构造的条目。

  2. 将多达 65,536 个条目读取到向量中,替换现有条目。

  3. 写出尽可能多的条目。

  4. 如果您准确读取了 65,536 个条目,请转到步骤 2。

  5. 停下来,你已经完成了。

这将防止您交替读取和写入两个不同的文件,从而显着减少查找活动。它还将允许您进行更少的write调用,从而减少复制和缓冲逻辑。

于 2013-02-07T20:57:09.820 回答