如何让IOStream表现得更好? P.大多数C++学习者在使用C++语言编写代码时,更喜欢使用 PROTFF />代码> SCANF函数族。
虽然我承认我发现接口方式更好(特别是POSIX格式和本地化),但似乎一个压倒性的问题是性能 看看这个问题: <最好的答案是使用<代码> fSCANF,并且C++ <代码> IFSturi是慢速2-3倍。 我认为如果我们可以编译一个“提示”库来提高IOStreams的性能,哪些有效,哪些无效,那将是一件非常棒的事情 考虑的要点如何让IOStream表现得更好? P.大多数C++学习者在使用C++语言编写代码时,更喜欢使用 PROTFF />代码> SCANF函数族。,c++,optimization,iostream,c++-faq,c++-standard-library,C++,Optimization,Iostream,C++ Faq,C++ Standard Library,虽然我承认我发现接口方式更好(特别是POSIX格式和本地化),但似乎一个压倒性的问题是性能 看看这个问题: pubstebuf(缓冲区,大小)) 同步(std::ios\u base::与stdio同步) 区域设置处理(我们可以使用精简的区域设置,还是完全删除它?) 当然,也欢迎其他方法 注意:提到了Dietmar Kuhl的“新”实现,但我找不到关于它的很多细节。以前的引用似乎是死链接。有趣的是,你说C程序员在写C++时更喜欢Prtff,因为我看到很多代码是C,而不是使用 cOUT 和 i
- 缓冲(
)rdbuf()->pubstebuf(缓冲区,大小)
- 同步(
)std::ios\u base::与stdio同步
- 区域设置处理(我们可以使用精简的区域设置,还是完全删除它?)
注意:提到了Dietmar Kuhl的“新”实现,但我找不到关于它的很多细节。以前的引用似乎是死链接。有趣的是,你说C程序员在写C++时更喜欢Prtff,因为我看到很多代码是C,而不是使用<代码> cOUT <代码>和<代码> iSooS写输出。 使用通常可以通过直接使用
filebuf
获得更好的性能(Scott Meyers在有效的STL中提到了这一点),但是使用filebuf direct的文档相对较少,大多数开发人员更喜欢std::getline
,这在大多数情况下更简单
关于区域设置,如果您创建了facet,您通常会获得更好的性能,方法是使用所有facet创建一次区域设置,保存它,并将其嵌入到您使用的每个流中
最近我确实在这里看到了关于这个的另一个主题,所以这几乎是一个重复。以下是我到目前为止收集的内容: 缓冲: 如果默认情况下缓冲区非常小,则增加缓冲区大小肯定可以提高性能:
- 它减少了硬盘的点击次数
- 它减少了系统调用的数量
streambuf
实现来设置缓冲区
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 constructor
@iavr提供的警告:根据建议,最好在打开文件之前致电pubsetbuf
。不同的标准库实现具有不同的行为
区域设置处理:
区域设置可以执行字符转换、过滤,以及涉及数字或日期的更巧妙的技巧。它们经历了一个复杂的动态调度和虚拟调用系统,因此删除它们有助于减少惩罚
默认的C
区域设置意味着不执行任何转换,并且在机器之间是统一的。这是一个很好的默认值
同步:
我看不到使用此功能有任何性能改进
您可以使用sync_with_stdio
静态功能访问全局设置(std::ios_base的静态成员)
测量值:
玩这个游戏,我玩了一个简单的程序,在SUSE 10p3上使用-O2
使用gcc 3.4.2
编译
C:7.76532e+06C++:1.0874e+07 这意味着大约
20%
。。。对于默认代码。实际上,篡改缓冲区(在C或C++中)或同步参数(C++中)并没有产生任何改进
其他方面的结果:
@Irfy在g++4.7.2-2ubuntu1,-O3上,虚拟化Ubuntu 11.10,3.5.0-25-generic,x86_64,足够的ram/cpu,196MB的几个“find/>>largefile.txt”运行
C:634572
C++:473222
C++快25%
@g++4.4.5,-O3上的Matteo Italia,Ubuntu Linux 10.10 x86_64,带有一个180 MB的随机文件
C:910390C++:776016 C++快17% @Bogatyr基于g++i686-apple-darwin10-g++-4.2.1(GCC)4.2.1(apple Inc.build 5664),mac mini,4GB ram,空闲,本测试使用168MB数据文件除外 C:4.34151e+06
C++:9.14476e+06 C++111%慢 @clang++3.8.0-2ubuntu4上的Asu,Kubuntu 16.04 Linux 4.8-rc3,8GB ram,i5 Haswell,关键SSD,88MB数据文件(tar.xz存档) C:270895 C++:162799 C++速度提高66% 所以答案是:这是一个实施质量问题,实际上取决于平台:/ 这里为那些对基准测试感兴趣的人提供了完整的代码:
#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'\n";
}
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 << "\n"
"C++: " << cpptime << "\n";
return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
模板
双基准(Func f,size\u t迭代)
{
f();
时间值a,b;
gettimeofday(&a,0);
对于(;迭代-->0;)
{
f();
}
gettimeofday(&b,0);
返回(b.tv_sec*(未签名整数)1e6+b.tv_usec)-
(a.tv_sec*(无符号整数)1e6+a.tv_usec);
}
结构CRead
{
CRead(char const*filename):_filename(filename){}
void运算符()(){
FILE*FILE=fopen(_文件名,“r”);
整数计数=0;
而(fscanf(文件,'%s',_buffer)==1){++count;}
fclose(文件);
}
char const*_文件名;
字符缓冲区[1024];
};
结构CppRead
{
CppRead(char const*filename):_filename(filename),_buffer(){}
枚举{BufferSize=16184};
void运算符()(){
std::ifstream文件(_文件名,std::ifstream::in);
//删除扩展缓冲区的注释
file.rdbuf()->pubstebuf(_buffer,BufferSize);
整数计数=0;
std::字符串s;
而(文件>>s){++count;}
}
char const*_文件名;
字符缓冲区[BufferSize];
};
int main(int argc,char*argv[])
{
迭代次数的大小=1;
如果(argc>1){iterations=atoi(argv[1]);}
char const*oldLocale=setlocale(LC_ALL,“C”);
if(strcmp(oldLocale,“C”)!=0){
std::cout还有两项改进:
问题std::cin.tie(
#include <iostream>
using namespace std;
int main()
{
ios_base::sync_with_stdio(false);
int i;
while(cin >> i)
cout << i << '\n';
}
#include <iostream>
using namespace std;
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
int i;
while(cin >> i)
cout << i << '\n';
cout.flush();
}
work@mg-K54C ~ $ time ./test1 < test.in > test1.in
real 0m3.140s
user 0m0.581s
sys 0m2.560s
work@mg-K54C ~ $ time ./test2 < test.in > test2.in
real 0m0.234s
user 0m0.234s
sys 0m0.000s
#include <iostream>
using namespace std;
int main()
{
ios_base::sync_with_stdio(false);
for(int i = 0; i < 1179648; ++i)
cout << i << endl;
}
#include <iostream>
using namespace std;
int main()
{
ios_base::sync_with_stdio(false);
for(int i = 0; i < 1179648; ++i)
cout << i << '\n';
}
work@mg-K54C ~ $ time ./test1 > test1.in
real 0m2.946s
user 0m0.404s
sys 0m2.543s
work@mg-K54C ~ $ time ./test2 > test2.in
real 0m0.156s
user 0m0.135s
sys 0m0.020s