C:634572C++:473222C++ 快 25%@Matteo Italia 在 g++ 4.4.5、-O3、Ubuntu Linux 10.10 x86_64 上使用一个随机的 180 MB 文件电话:910390C++:776016C++ 快 17%@Bogatyr on g++ i686-apple-darwin10-g++-4.2.1 (GCC) 4.2.1(Apple Inc. build 5664),mac mini,4GB 内存,空闲,除了这个测试有 168MB 数据文件C : 4.34151e+06C++:9.14476e+06C++ 慢 111%@Asu on clang++ 3.8.0-2ubuntu4、Kubuntu 16.04 Linux 4.8-rc3、8GB ram、i5 Haswell、Crucial SSD、88MB 数据文件(tar.xz 存档)C : 270895C++:162799C++ 快 66%所以答案是:这是一个实施质量问题,实际上取决于平台:/对于那些对基准测试感兴趣的人,这里有完整的代码:#include #include #include #include <cmath>#include #include 模板 双基准(Func f,size_t 迭代){F();时间值 a, b;gettimeofday(&a, 0);for (; 迭代 --> 0;){F();}gettimeofday(&b, 0);返回 (b.tv_sec * (unsigned int)1e6 + b.tv_usec) -(a.tv_sec * (unsigned int)1e6 + a.tv_usec);}结构 CRead{CRead(char const* 文件名): _filename(filename) {}无效运算符()(){FILE* file = fopen(_filename, "r");整数计数 = 0;while ( fscanf(file,"%s", _buffer) == 1 ) { ++count;}fclose(文件);}字符常量* _文件名;字符_缓冲区[1024];};结构 CppRead{CppRead(char const* filename): _filename(filename), _buffer() {}枚举 { BufferSize = 16184 };无效运算符()(){std::ifstream 文件(_filename, std::ifstream::in);//删除扩展缓冲区的注释file.rdbuf()->pubsetbuf(_buffer, BufferSize);整数计数 = 0;std::string s;而(文件>> s){ ++计数;}}字符常量* _文件名;char _buffer[BufferSize];};int main(int argc, char* argv[]){size_t 迭代次数 = 1;if (argc > 1) { 迭代 = atoi(argv[1]);}char const* oldLocale = setlocale(LC_ALL,"C");如果(strcmp(oldLocale,C")!= 0){std::cout <<替换了旧的语言环境"<<oldLocaleMost C++ users that learned C prefer to use the printf / scanf family of functions even when they're coding in C++.Although I admit that I find the interface way better (especially POSIX-like format and localization), it seems that an overwhelming concern is performance.Taking at look at this question:It seems that the best answer is to use fscanf and that the C++ ifstream is consistently 2-3 times slower.I thought it would be great if we could compile a repository of "tips" to improve IOStreams performance, what works, what does not.Points to considerbuffering (rdbuf()->pubsetbuf(buffer, size))synchronization (std::ios_base::sync_with_stdio)locale handling (Could we use a trimmed-down locale, or remove it altogether ?)Of course, other approaches are welcome.Note: a "new" implementation, by Dietmar Kuhl, was mentioned, but I was unable to locate many details about it. Previous references seem to be dead links. 解决方案 Here is what I have gathered so far:Buffering:If by default the buffer is very small, increasing the buffer size can definitely improve the performance:it reduces the number of HDD hitsit reduces the number of system callsBuffer can be set by accessing the underlying streambuf implementation.char Buffer[N];std::ifstream file("file.txt");file.rdbuf()->pubsetbuf(Buffer, N);// the pointer reader by rdbuf is guaranteed// to be non-null after successful constructorWarning courtesy of @iavr: according to cppreference it is best to call pubsetbuf before opening the file. Various standard library implementations otherwise have different behaviors.Locale Handling:Locale can perform character conversion, filtering, and more clever tricks where numbers or dates are involved. They go through a complex system of dynamic dispatch and virtual calls, so removing them can help trimming down the penalty hit.The default C locale is meant not to perform any conversion as well as being uniform across machines. It's a good default to use.Synchronization:I could not see any performance improvement using this facility.One can access a global setting (static member of std::ios_base) using the sync_with_stdio static function.Measurements:Playing with this, I have toyed with a simple program, compiled using gcc 3.4.2 on SUSE 10p3 with -O2.Which represents a slowdown of about 20%... for the default code. Indeed tampering with the buffer (in either C or C++) or the synchronization parameters (C++) did not yield any improvement.Results by others:C++ 25% fasterC++ 17% fasterC++ 111% slowerC++ 66% fasterSo the answer is: it's a quality of implementation issue, and really depends on the platform :/The code in full here for those interested in benchmarking:#include <fstream>#include <iostream>#include <iomanip>#include <cmath>#include <cstdio>#include <sys/time.h>template <typename Func>double benchmark(Func f, size_t iterations){ f(); timeval a, b; gettimeofday(&a, 0); for (; iterations --> 0;) { f(); } gettimeofday(&b, 0); return (b.tv_sec * (unsigned int)1e6 + b.tv_usec) - (a.tv_sec * (unsigned int)1e6 + a.tv_usec);}struct CRead{ CRead(char const* filename): _filename(filename) {} void operator()() { FILE* file = fopen(_filename, "r"); int count = 0; while ( fscanf(file,"%s", _buffer) == 1 ) { ++count; } fclose(file); } char const* _filename; char _buffer[1024];};struct CppRead{ CppRead(char const* filename): _filename(filename), _buffer() {} enum { BufferSize = 16184 }; void operator()() { std::ifstream file(_filename, std::ifstream::in); // comment to remove extended buffer file.rdbuf()->pubsetbuf(_buffer, BufferSize); int count = 0; std::string s; while ( file >> s ) { ++count; } } char const* _filename; char _buffer[BufferSize];};int main(int argc, char* argv[]){ size_t iterations = 1; if (argc > 1) { iterations = atoi(argv[1]); } char const* oldLocale = setlocale(LC_ALL,"C"); if (strcmp(oldLocale, "C") != 0) { std::cout << "Replaced old locale '" << oldLocale << "' by 'C'"; } char const* filename = "largefile.txt"; CRead cread(filename); CppRead cppread(filename); // comment to use the default setting bool oldSyncSetting = std::ios_base::sync_with_stdio(false); double ctime = benchmark(cread, iterations); double cpptime = benchmark(cppread, iterations); // comment if oldSyncSetting's declaration is commented std::ios_base::sync_with_stdio(oldSyncSetting); std::cout << "C : " << ctime << "" "C++: " << cpptime << ""; return 0;} 这篇关于如何让 IOStream 性能更好?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云! 07-23 06:39