在 C++ 中,如何使用多个线程读取一个文件?
Posted
技术标签:
【中文标题】在 C++ 中,如何使用多个线程读取一个文件?【英文标题】:In C++, How to read one file with multiple threads? 【发布时间】:2013-07-31 13:39:20 【问题描述】:我正在使用 Windows 7、64 位、8 核的 VS2012 从本地硬盘读取 .csv 文件。
我正在读取的文件有 50,000 多行,每行有 200 多个属性,因此读取数据并将它们提供给相应的变量非常耗时。因此,我想知道是否可以通过多线程来加快速度,即每个线程读取文件的一部分。
我在谷歌上搜索过,发现有人说,由于硬盘驱动器不是多线程的,因此使用多个线程来这样做实际上会减慢速度。 这是真的吗?
如果可以读取具有多个线程的文件,谁能给我一个我可以学习的例子吗?
另外,是否可以将线程或任务显式分配给 CPU 内核?
最后一个问题:我已经用 Python 读取了同一个文件,并且它在几秒钟内就完成了。 我可以知道为什么 Python 的读取速度比 C++ 快吗?
【问题讨论】:
一般来说,从文件中读取多线程确实会减慢速度。该程序可能是多线程的,但请考虑磁盘控制器和读/写磁头...可以构造此规则的例外情况,例如并行文件系统(您会知道是否有),执行以下操作的计算读取文件块之间的大量处理,其他一些情况。 您可以让一个线程读取文件,然后将块传递给多个解析器线程。然后,理想情况下,您有一个用于保存数据的并发集合,因此工作线程可以在那里快速有效地插入解析结果(假设您需要将所有数据放在内存中的一个数据结构中)。 除非在读取数据后处理数据的计算量非常大,否则使用多个线程读取文件将无济于事。如果不了解您是如何在 Python 和 C++ 中实现文件读取的,就很难知道为什么您会在 C++ 中看到更差的性能。我猜你使用 C++ API 不正确或不好。 @hyde 非常感谢。这是个好主意。 @Kylos Python代码不是我的,但是我知道原来的coder是用csv.py来解析csv文件的(我对python不太了解,估计csv.py是一个包或预编译库)。另一方面,我在 C++ 中使用 STL 编写代码,并且操作是显式执行的。 【参考方案1】:读取文件需要使用任何语言或操作系统进行系统调用,这意味着调用底层操作系统,并等待它为您将文件内容放入内存(假设您通过了操作系统的安全检查以及所有这些)。多线程读取文件确实会减慢您的速度,因为您会进行更多的系统调用,这会使您退出程序执行并将控制权交给操作系统。
因此,最好的建议是 hyde's - 如果需要,可能会将文件解析拆分到多个线程。但是,如果您能够在几秒钟内解析这么大的文件,我会说这并不值得。例如,如果您正在运行一个图形应用程序,您肯定希望为文件加载保留一个单独的线程,这样您就不会冻结您的 UI。
关于速度问题,我猜有两个主要问题。首先,我怀疑python默认通过内存缓冲区读取它的文件,这会加快执行速度。如果您可以缓冲文件读取(这样您可以减少系统调用),您可能会看到一些性能提升。另一个问题是您在 Python 和 C++ 中使用哪些数据结构来加载/解析数据。在不了解您的代码的情况下,我无法提出任何具体的建议,但花一点时间研究/思考适用于您的程序的不同数据结构可能会很有用。请记住,Python 和 C++ 的数据结构具有非常不同的性能配置文件,因此在 Python 中运行良好的数据结构在 C++ 中可能是更糟糕的选择。
编辑:在 C++ STL 中使用文件缓冲的简单示例来自 http://www.cplusplus.com/reference/
// read a file into buffer - sgetn() example
#include <iostream> // std::cout, std::streambuf, std::streamsize
#include <fstream> // std::ifstream
int main ()
char* contents;
std::ifstream istr ("test.txt");
if (istr)
std::streambuf * pbuf = istr.rdbuf();
std::streamsize size = pbuf->pubseekoff(0,istr.end);
pbuf->pubseekoff(0,istr.beg); // rewind
contents = new char [size];
pbuf->sgetn (contents,size);
istr.close();
std::cout.write (contents,size);
return 0;
【讨论】:
嗨,马克斯。非常感谢您的回答。这真的很有启发性。你能给我一个简单的例子来告诉我如何设置阅读缓冲区吗?它必须下降到硬件级别吗?再次感谢。 假设您使用的是 C++ STL,您可以在此处查看 std::filebuf 的文档:cplusplus.com/reference/fstream/filebuf 这种来回查找的方法正是人们抱怨微软的bcp
除了普通文件之外的任何东西的原因,作为旁注。您可能喜欢使用std::vector<>
而不是普通的char*
数组,这里没有充分的理由使用后者。以上是关于在 C++ 中,如何使用多个线程读取一个文件?的主要内容,如果未能解决你的问题,请参考以下文章