访问文件中的单个字符效率低下?(C++)
Accessing individual characters in a file inefficient? (C++)
我一直认为,在处理文本文件时,首先将内容(或部分内容)读取到std::string或char数组中会更高效,因为据我所知,文件是以比单个字符大得多的块从内存中读取的。然而,我听说现代操作系统通常不会直接从文件中读取,这使得我手动缓冲输入几乎没有什么好处。
假设我想确定文本文件中某个字符的编号。以下会不会效率低下?
while (fin.get(ch)) {
if (ch == 'n')
++char_count;
}
当然,我想这将取决于文件大小,但有人对什么是最佳方法有任何一般规则吗?
这里很大程度上取决于性能对您/您的应用程序的关键程度。反过来,这往往取决于你处理的文件有多大——如果你处理的是几十或几百KB的文件,你通常应该只写最简单的代码,而不必太担心——你能做的任何事情基本上都是即时的,所以优化代码不会真正起到多大作用。
另一方面,如果你正在处理大量数据——大约几十兆字节或更多,那么效率上的差异可能会变得相当大。除非你采取相当具体的步骤来绕过它(例如使用read
),否则所有的读取都将被缓冲——但这并不意味着和都将是相同的速度(甚至必须非常接近相同的速度)。
例如,让我们试着快速测试几种不同的方法,以实现您所要求的基本功能:
#include <stdio.h>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <fstream>
#include <time.h>
#include <string>
#include <algorithm>
unsigned count1(FILE *infile, char c) {
int ch;
unsigned count = 0;
while (EOF != (ch=getc(infile)))
if (ch == c)
++count;
return count;
}
unsigned int count2(FILE *infile, char c) {
static char buffer[4096];
int size;
unsigned int count = 0;
while (0 < (size = fread(buffer, 1, sizeof(buffer), infile)))
for (int i=0; i<size; i++)
if (buffer[i] == c)
++count;
return count;
}
unsigned count3(std::istream &infile, char c) {
return std::count(std::istreambuf_iterator<char>(infile),
std::istreambuf_iterator<char>(), c);
}
unsigned count4(std::istream &infile, char c) {
return std::count(std::istream_iterator<char>(infile),
std::istream_iterator<char>(), c);
}
template <class F, class T>
void timer(F f, T &t, std::string const &title) {
unsigned count;
clock_t start = clock();
count = f(t, 'N');
clock_t stop = clock();
std::cout << std::left << std::setw(30) << title << "tCount: " << count;
std::cout << "tTime: " << double(stop-start)/CLOCKS_PER_SEC << "n";
}
int main() {
char const *name = "test input.txt";
FILE *infile=fopen(name, "r");
timer(count1, infile, "ignore");
rewind(infile);
timer(count1, infile, "using getc");
rewind(infile);
timer(count2, infile, "using fread");
fclose(infile);
std::ifstream in2(name);
in2.sync_with_stdio(false);
timer(count3, in2, "ignore");
in2.clear();
in2.seekg(0);
timer(count3, in2, "using streambuf iterators");
in2.clear();
in2.seekg(0);
timer(count4, in2, "using stream iterators");
return 0;
}
我用一个大约44兆字节的文件作为输入来运行这个程序。当用VC++2012编译时,我得到了以下结果:
ignore Count: 400000 Time: 2.08
using getc Count: 400000 Time: 2.034
using fread Count: 400000 Time: 0.257
ignore Count: 400000 Time: 0.607
using streambuf iterators Count: 400000 Time: 0.608
using stream iterators Count: 400000 Time: 5.136
使用相同的输入,但使用g++4.7.1:编译
ignore Count: 400000 Time: 0.359
using getc Count: 400000 Time: 0.339
using fread Count: 400000 Time: 0.243
ignore Count: 400000 Time: 0.697
using streambuf iterators Count: 400000 Time: 0.694
using stream iterators Count: 400000 Time: 1.612
因此,即使所有的读取都是缓冲的,我们也看到g++的变化约为8:1,VC++的变化为20:1。当然,我还没有测试(甚至接近)阅读输入的所有可能的方式。如果我们测试更多的阅读技巧,我怀疑我们会看到更多的时间,但我可能错了。无论我们是否这样做,我们都看到了足够多的变化,至少如果你正在处理大量数据,你很有理由选择一种技术来提高处理速度。
编辑:令我惊讶的是,杰瑞的号码竟然是。我本以为,通过分块读取和解析所获得的任何效率都会与从文件中读取的成本相比相形见绌。我真的很想知道这些时间花在了哪里,以及当文件没有缓存时,变化会降低多少。尽管如此,我还是要推荐Jerry的答案,尤其是他指出的,在你知道自己有性能问题之前,你真的不应该担心。
它在很大程度上取决于上下文,由于代码周围的上下文不存在,所以很难说。
毫无疑问,正如其他人所说,您的操作系统可能正在为您缓存文件的至少一小部分。。。然而,在用户和内核之间来回切换是非常昂贵的,这可能就是您的瓶颈所在。
如果在此代码之前插入fin.rdbuf()->pubsetbuf(NULL, 65536);
,您可能会注意到显著的加速。这是对标准库的一个提示,可以尝试一次从内核读取65536字节,并将其保存以供以后使用,而不是在用户和内核之间为每个字符来回切换。
- 为什么当我解模块化时,这个C++代代码"效率较低"?
- 代码的效率. 转到和函数调用
- 对于循环C++可能效率低下
- 内存效率表示最短路径的方法?
- 如何提高该函数的运行效率?
- 效率:标准::数组与标准::矢量
- 如何提高BST的搜索操作效率?
- 字符串引用参数的效率C++
- 提高基于组件的游戏引擎的效率
- 在 c++ 中使用带有映射的插入效率
- 关于效率的问题
- 在SQLITE数据库中写入记录需要花费大量时间.如何提高刀片操作效率?
- 寻求提高Microsoft密封库计算效率的方法
- 做对了一个类似竞争的问题,但需要帮助来提高效率
- C++ - 与 Numpy 中的矢量版本相比,Argsort 效率低的矢量版本实现
- C++,在对象内分配多个数据时,堆栈分配是否更有效? 在下面的程序中,类A_Heap的效率会更低吗?
- visual C++|循环效率
- 我创建了一个库,想知道设计是否效率低下
- 矩阵rowSums()与colSums(()在R与Rcpp与Armadillo中的效率
- 共享指针的复制和交换效率