c++有效的缓冲文本和有条件地将部分写入文本文件的方法
C++ efficient way to buffer text and conditionally write portions to a text file
我正在构建包含数亿行的CSV文本文件。对record
函数的每次调用形成一行文本并将其缓冲到stringstream
中。周期性地,根据record
函数的输入,缓冲行要么被写入文件,要么被丢弃。我猜大约75%的缓冲行在大多数情况下最终被写入文件。
所以,我真正在做的是形成一堆文本行,决定是扔掉它们还是把它们写进文件,然后一遍又一遍地重复很多次。
下面是我的代码的简化示例。设CONDITION1
、CONDITION2
为简单布尔表达式,包含x
、y
、z
;它们不需要花费大量的时间来评估。代码确实很慢,我可以看到几个原因:通常使用stringstreams
,特别是反复调用stringstream::str()
和stringstream::str(const string&)
。
问题:我怎样才能使它更快?
注意:我假设(或知道)使用std::string
来保存一堆文本会更快,但我担心使用double
变量(如x
)构建文本所需的额外转换。(在实际情况中,大约有10个不同的双变量以逗号分隔并在一起。)
std::ofstream outf;
stringstream ss;
// open outf
void record(const double x, const bool y, const int z) {
ss << x << ", ";
if(y) ss << "YES, ";
else ss << "NO, ";
ss << z << "n";
if(CONDITION1) {
if(CONDITION2)
outf << ss.str();
ss.str(std::string());
}
}
假设这是可能的,那么第一个也是最明显的优化就是在执行任何转换之前检查条件。与此同时,您可以避免从stringstream的内容创建string
对象,而只是直接从stringstream
的缓冲区复制到ostream
的缓冲区。我还可能使用一个向量来处理布尔转换。特别是对于不包括短字符串优化的实现,您还可以通过预先初始化一个空字符串来清除stringstream来节省一些时间:
std::ofstream outf;
stringstream ss;
namespace {
char const *names[] = { "No, ", "Yes, "};
std::string clear;
}
// open outf
void record(const double x, const bool y, const int z) {
if (!(CONDITION1 && CONDITION2))
return;
ss << x << ", ";
ss << names[y];
ss << z << "n";
outf << ss.rdbuf();
ss.str(clear);
}
假设您实际上可以像这样尽早检查条件,那么您可能也可以完全消除stringstream
。
void record(const double x, const bool y, const int z) {
if (!(CONDITION1 && CONDITION2))
return;
outf << x << ", "
<< names[y]
<< z << "n";
}
老实说,我怀疑这是否会产生巨大的差异,但这些是我在没有看到你真正关心的代码的情况下立即想到的最佳猜测。
Background
有两个基本问题导致经济放缓:
- 获取数据
- 解析数据
这些通常是占用时间最多的项目。
获取数据
获取数据的最佳过程是保持数据流入内存。这可能意味着从读取大块数据到使用线程保持读取。如果你正在使用硬盘,它们不喜欢停下来。他们有启动和定位部门的开销。可以通过读取大块(每个请求读取更多数据)来减少启动。
解析数据
在搜索分隔字符和将文本表示转换为内部表示时浪费了时间。
固定的字段长度是最快的解析。不需要搜索,数据在固定字符位置。这消除了搜索分隔字符的时间。
同样,固定字段更容易从缓冲区中处理。对于可变长度的记录,记录可能跨越缓冲区的末尾,从而导致执行一些额外的代码。
减少分支
处理器倾向于连续执行指令。当他们碰到分支指令时,他们会有点不安。这意味着它们必须从其他地方获取指令。条件更糟。在条件解决之前,提取机制不能提取(尽管在提取算法上有更多的研究来加速它们)。总之,减少瓶颈区域的分支数量。
概要文件。那就试试这些技巧吧。概要文件。比较"前"answers"后"配置文件来确定增益。
去掉iostreams
。甚至不计算文件I/O本身,仅仅构建您的stringstream
就已经使您的性能降低了一个数量级以上,而不是磁盘应有的能力。(见这里的证据)。
使用Jerry的提前退出技巧,然后考虑使用普通C字符串处理函数构建缓冲区,如strncat
(或"安全"版本,负责缓冲区溢出预防,因此您不必这样做)或snprintf
。
c++ iostreams几乎可以胜任使用filebuf
将准备好的缓冲区传输到磁盘,但是您可能仍然需要对FILE*
和/或OS文件访问api进行基准测试。
另外,在将几十条记录传递到磁盘之前,不要害怕将它们缓冲到应用程序级缓冲区中。
- 文本文件中的单词链表
- 在C++程序中输入的文本文件将不起作用,除非文本被复制和粘贴
- 如何将内容数组写入文本文件?
- 无法通过空白将文本文件行分隔为矢量
- 我正在使用嵌套的while循环来解析具有多行的文本文件,但由于某种原因,它只通过第一行,我不知道为什么
- C++将文本文件中的数据读取到结构数组中
- 在指针的帮助下,文本文件中单词的频率
- 将字符指针十六进制转换为字符串并保存在文本文件C++中
- 将值从二维数组输出到文本文件
- 如何在c++中从文本文件中逐行读取整数
- 从文本文件中读取时钟时间和事件时间并进行处理
- 如何从文本文件中读取值和数组
- 如何在C++中确定文本文件中的元素是字符还是数字
- C++试图读取一个文件并输出到另一个文本文件
- 如何通过套接字将文本文件的内容从服务器发送到客户端
- 已修改的LinkedList未在文本文件本身中更新
- C++文本文件的获取线
- 为什么C++的文件 I/O 在读取文本文件时忽略初始空行?我怎样才能让它不这样做?
- 打印逐行存储的文本文件
- C++文本文件输入