读取C++中的大型CSV文件(~4GB)
Read large CSV file in C++(~4GB)
我想读取一个大的CSV文件并将其存储到映射中。我开始只是阅读文件,看看它需要多长时间来处理。这是我的循环:
while(!gFile.eof()){
gFile >> data;
}
处理包含3500万行和六列的csv文件大约需要35分钟。有什么办法加快速度吗?对SO来说还很陌生,所以如果问得不对,请道歉。
背景
文件是流设备或概念。读取文件最有效的用途是保持数据流(流动)。每一笔交易都有一笔开销。数据传输越大,开销的影响就越小。因此,我们的目标是保持数据的流动性。
内存比文件访问快
搜索内存比搜索文件快很多倍。因此,搜索"单词"或分隔符将比逐个字符读取文件以查找分隔符更快。
方法1:逐行
使用std::getline
比使用operator>>
快得多。尽管输入代码可以读取数据块;您只执行一个事务来读取记录,而每列执行一个交易。请记住,保持数据流动,并且在内存中搜索列会更快。
方法2:块读取
本着保持流流动的精神,将内存块读取到缓冲区(大缓冲区)中。处理缓冲区中的数据。这比逐行读取更有效,因为您可以用一个事务读取多行数据,从而减少事务的开销。
需要注意的一点是,您可能有一个记录跨越缓冲区边界,因此您需要想出一个算法来处理这个问题。执行惩罚很小,每个事务只发生一次(考虑事务的这部分开销)。
方法3:多个线程
本着保持数据流的精神,您可以创建多个线程。一个线程负责或将数据读取到缓冲区,而另一个线程处理来自缓冲区的数据。这种技术将有更好的运气保持数据的流动。
方法四:双缓冲&多个线程
这采用了上面的方法3并添加了多个缓冲区。读取线程可以填充一个缓冲区,然后开始填充第二个缓冲区。数据处理线程将等待,直到第一个缓冲区被填满后再处理数据。该技术用于更好地将读取数据的速度与处理数据的速度相匹配。
方法5:内存映射文件
使用内存映射文件,操作系统会根据需要处理将文件读取到内存的操作。您需要编写的代码更少,但无法控制何时将文件读入内存。这仍然比逐场读取要快。
让我们从瓶颈开始。
- 从磁盘读取
- 解码数据
- 存储在地图中
- 内存速度
- 内存量
从磁盘读取
- 如果你读得不够快,无法使用所有磁盘上的带宽你可以走得更快。忽略所有其他步骤,只读取
- 首先在流内添加缓冲区
- 设置阅读提示
- 使用mmap
- 4GB是一个微不足道的大小,如果你还没有32 GB的升级
- 买M.2磁盘太慢
- 还是要放慢速度,然后更奇特,更换磁盘驱动程序,转储操作系统。镜像磁盘,只有你$$是限制
解码数据
- 如果数据在长度相同的行中,则所有解码都可以并行进行,仅受内存带宽的限制
- 如果线路长度只有一点谨慎,则可以并行地查找线路末端,然后进行并行解码
- 如果行的顺序对最终映射无关紧要,只需将文件拆分为#hardwarethreads部分,并让每个部分处理它们的部分,直到下一个线程部分中的第一个换行符为止
- 内存带宽很可能在CPU接近耗尽之前就已经达到
存储在地图中
- 希望您已经提前考虑过这个映射,因为没有一个std映射是线程安全的
- 如果您不关心顺序,可以使用std::数组,并且可以在满内存带宽下运行
- 假设您想使用std::unordereded_map,则存在每次写入后都需要更新大小的问题,因此实际上您只能使用1个线程对其进行写入
- 您可以一次使用一个线程进行更新,而另一个线程则预计算记录的哈希值
- 使用一个线程进行写操作的问题是,几乎每一次写操作都将是缓存未命中,严重限制了速度
- 因此,如果这还不够快,请滚动您自己的hashmap,而不需要每次写入都必须更新的大小
- 为了确保线程安全,您还需要保护写入,拥有一个互斥会使您的速度与单个写入程序一样慢或更慢
- 你可以试着把它锁上,然后免费等待。。。如果你不是专家,你反而会头疼得厉害
- 如果您为hash选择了一个bucket设计,那么您可以使X倍数量的编写器线程成为互斥对象,使用hash值来选择互斥对象。额外的互斥增加了两个线程不会发生冲突的可能性
内存速度
- 每条线将通过内存总线传输至少4次,一次从磁盘传输到ram(如果驱动器不好,至少还会传输一次),一次在数据解码时传输,一次当映射发出读取请求时传输,另一次在映射写入时传输
- 如果驱动程序写入高速缓存,一个好的设置可以再节省一次内存访问,因此不解码将导致LLC未命中
内存量
- 您应该有足够的内存来容纳整个文件、数据结构和一些中间数据
- 检查RAM是否比编程时间便宜
- .cpp和.h文件中的模板专用化声明
- 为什么两个不同的未命名名称空间可以共存于一个cpp文件中
- 文本文件中的单词链表
- CMake-按正确顺序将项目与C运行时对象文件链接
- 使用新行和不使用新行读取文件
- 在C++程序中输入的文本文件将不起作用,除非文本被复制和粘贴
- 挂起和取消挂起一个文件DLL
- 如何确定我已使用非编码文件到达 EOF?
- 命名空间中具有.h和.cpp文件的类
- 如何使用ndk-build.cmd构建Android.so文件
- 从包含m行的文件中提取n行,必要时(惰性地)重复该文件
- 读取文件并输入到矢量中
- 读取C++中的大型CSV文件(~4GB)
- 为什么在 32 位 armv7l 上 mmap 一个 4GB 文件成功
- 如何在32位系统上读取4GB文件
- 在c++中查找大于4GB的文件
- 在 64 位(或 32 位)Windows 上以 32 位进程访问 >3,3,4GB 文件
- 如何使用C++在>4GB文件中写入数据?
- 在windows中查找超过4gb的正确文件大小
- 在C++中,将大型二进制(1GB-4GB)文件加载到内存中的最快方法是什么