读取C++中的大型CSV文件(~4GB)

Read large CSV file in C++(~4GB)

本文关键字:4GB 文件 CSV C++ 大型 读取      更新时间:2023-10-16

我想读取一个大的CSV文件并将其存储到映射中。我开始只是阅读文件,看看它需要多长时间来处理。这是我的循环:

while(!gFile.eof()){
gFile >> data;
}

处理包含3500万行和六列的csv文件大约需要35分钟。有什么办法加快速度吗?对SO来说还很陌生,所以如果问得不对,请道歉。

背景
文件是流设备或概念。读取文件最有效的用途是保持数据流(流动)。每一笔交易都有一笔开销。数据传输越大,开销的影响就越小。因此,我们的目标是保持数据的流动性。

内存比文件访问快
搜索内存比搜索文件快很多倍。因此,搜索"单词"或分隔符将比逐个字符读取文件以查找分隔符更快。

方法1:逐行
使用std::getline比使用operator>>快得多。尽管输入代码可以读取数据块;您只执行一个事务来读取记录,而每列执行一个交易。请记住,保持数据流动,并且在内存中搜索列会更快。

方法2:块读取
本着保持流流动的精神,将内存块读取到缓冲区(大缓冲区)中。处理缓冲区中的数据。这比逐行读取更有效,因为您可以用一个事务读取多行数据,从而减少事务的开销。

需要注意的一点是,您可能有一个记录跨越缓冲区边界,因此您需要想出一个算法来处理这个问题。执行惩罚很小,每个事务只发生一次(考虑事务的这部分开销)。

方法3:多个线程
本着保持数据流的精神,您可以创建多个线程。一个线程负责或将数据读取到缓冲区,而另一个线程处理来自缓冲区的数据。这种技术将有更好的运气保持数据的流动。

方法四:双缓冲&多个线程
这采用了上面的方法3并添加了多个缓冲区。读取线程可以填充一个缓冲区,然后开始填充第二个缓冲区。数据处理线程将等待,直到第一个缓冲区被填满后再处理数据。该技术用于更好地将读取数据的速度与处理数据的速度相匹配。

方法5:内存映射文件
使用内存映射文件,操作系统会根据需要处理将文件读取到内存的操作。您需要编写的代码更少,但无法控制何时将文件读入内存。这仍然比逐场读取要快。

让我们从瓶颈开始。

  1. 从磁盘读取
  2. 解码数据
  3. 存储在地图中
  4. 内存速度
  5. 内存量

从磁盘读取

  • 如果你读得不够快,无法使用所有磁盘上的带宽你可以走得更快。忽略所有其他步骤,只读取
  • 首先在流内添加缓冲区
  • 设置阅读提示
  • 使用mmap
  • 4GB是一个微不足道的大小,如果你还没有32 GB的升级
  • 买M.2磁盘太慢
  • 还是要放慢速度,然后更奇特,更换磁盘驱动程序,转储操作系统。镜像磁盘,只有你$$是限制

解码数据

  • 如果数据在长度相同的行中,则所有解码都可以并行进行,仅受内存带宽的限制
  • 如果线路长度只有一点谨慎,则可以并行地查找线路末端,然后进行并行解码
  • 如果行的顺序对最终映射无关紧要,只需将文件拆分为#hardwarethreads部分,并让每个部分处理它们的部分,直到下一个线程部分中的第一个换行符为止
  • 内存带宽很可能在CPU接近耗尽之前就已经达到

存储在地图中

  • 希望您已经提前考虑过这个映射,因为没有一个std映射是线程安全的
  • 如果您不关心顺序,可以使用std::数组,并且可以在满内存带宽下运行
  • 假设您想使用std::unordereded_map,则存在每次写入后都需要更新大小的问题,因此实际上您只能使用1个线程对其进行写入
  • 您可以一次使用一个线程进行更新,而另一个线程则预计算记录的哈希值
  • 使用一个线程进行写操作的问题是,几乎每一次写操作都将是缓存未命中,严重限制了速度
  • 因此,如果这还不够快,请滚动您自己的hashmap,而不需要每次写入都必须更新的大小
  • 为了确保线程安全,您还需要保护写入,拥有一个互斥会使您的速度与单个写入程序一样慢或更慢
  • 你可以试着把它锁上,然后免费等待。。。如果你不是专家,你反而会头疼得厉害
  • 如果您为hash选择了一个bucket设计,那么您可以使X倍数量的编写器线程成为互斥对象,使用hash值来选择互斥对象。额外的互斥增加了两个线程不会发生冲突的可能性

内存速度

  • 每条线将通过内存总线传输至少4次,一次从磁盘传输到ram(如果驱动器不好,至少还会传输一次),一次在数据解码时传输,一次当映射发出读取请求时传输,另一次在映射写入时传输
  • 如果驱动程序写入高速缓存,一个好的设置可以再节省一次内存访问,因此不解码将导致LLC未命中

内存量

  • 您应该有足够的内存来容纳整个文件、数据结构和一些中间数据
  • 检查RAM是否比编程时间便宜