Dan*_*ons 5 c++ performance iostream
我试图理解如何提高这个 C++ 代码的性能,使其与它所基于的 C 代码相提并论。C 代码如下所示:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct point {
double x, y;
} point_t;
int read_point(FILE *fp, point_t *p) {
char buf[1024];
if (fgets(buf, 1024, fp)) {
char *s = strtok(buf, " ");
if (s) p->x = atof(s); else return 0;
s = strtok(buf, " ");
if (s) p->y = atof(s); else return 0;
}
else
return 0;
return 1;
}
int main() {
point_t p;
FILE *fp = fopen("biginput.txt", "r");
int i = 0;
while (read_point(fp, &p))
i++;
printf("read %d points\n", i);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
C++ 代码如下所示:
#include <iostream>
#include <fstream>
using namespace std;
struct point {
double x, y;
};
istream &operator>>(istream &in, point &p) {
return in >> p.x >> p.y;
}
int main() {
point p;
ifstream input("biginput.txt");
int i = 0;
while (input >> p)
i++;
cout << "read " << i << " points" << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我喜欢 C++ 代码更短更直接,但是当我在我的机器上运行它们时,我得到了非常不同的性能(两者都在同一台机器上针对 138 MB 测试文件运行):
$ time ./test-c
read 10523988 points
1.73 real 1.68 user 0.04 sys
# subsequent runs:
1.69 real 1.64 user 0.04 sys
1.72 real 1.67 user 0.04 sys
1.69 real 1.65 user 0.04 sys
$ time ./test-cpp
read 10523988 points
14.50 real 14.36 user 0.07 sys
# subsequent runs
14.79 real 14.43 user 0.12 sys
14.76 real 14.40 user 0.11 sys
14.58 real 14.36 user 0.09 sys
14.67 real 14.40 user 0.10 sys
Run Code Online (Sandbox Code Playgroud)
连续多次运行任一程序不会改变 C++ 版本大约慢 10 倍的结果。
文件格式只是以空格分隔的双精度行,例如:
587.96 600.12
430.44 628.09
848.77 468.48
854.61 76.18
240.64 409.32
428.23 643.30
839.62 568.58
Run Code Online (Sandbox Code Playgroud)
有没有减少我缺少的开销的技巧?
编辑 1:使操作符内联似乎有一个非常小但可能检测到的影响:
14.62 real 14.47 user 0.07 sys
14.54 real 14.39 user 0.07 sys
14.58 real 14.43 user 0.07 sys
14.63 real 14.45 user 0.08 sys
14.54 real 14.32 user 0.09 sys
Run Code Online (Sandbox Code Playgroud)
这并不能真正解决问题。
编辑2:我正在使用clang:
$ clang --version
Apple LLVM version 7.0.0 (clang-700.0.72)
Target: x86_64-apple-darwin15.5.0
Thread model: posix
Run Code Online (Sandbox Code Playgroud)
我没有在 C 或 C++ 上使用任何优化级别,而且它们都在我的 Mac 上使用相同版本的 Clang 进行编译。可能是 OS X 10.11 上的 Xcode (/usr/bin/clang) 附带的版本。我认为如果我在一个而不是另一个中启用优化或使用不同的编译器,这会使问题变得模糊。
编辑3:用istream &operator>>其他东西替换
我已经重写了 istream 运算符,使其更接近 C 版本,并且得到了改进,但我仍然看到了大约 5 倍的性能差距。
inline istream &operator>>(istream &in, point &p) {
string line;
getline(in, line);
if (line.empty())
return in;
size_t next = 0;
p.x = stod(line, &next);
p.y = stod(line.substr(next));
return in;
}
Run Code Online (Sandbox Code Playgroud)
运行:
$ time ./test-cpp
read 10523988 points
6.85 real 6.74 user 0.05 sys
# subsequently
6.70 real 6.62 user 0.05 sys
7.16 real 6.86 user 0.12 sys
6.80 real 6.59 user 0.09 sys
6.79 real 6.59 user 0.08 sys
Run Code Online (Sandbox Code Playgroud)
有趣的是,编译它-O3是一个实质性的改进:
$ time ./test-cpp
read 10523988 points
2.44 real 2.38 user 0.04 sys
2.43 real 2.38 user 0.04 sys
2.49 real 2.41 user 0.04 sys
2.51 real 2.42 user 0.05 sys
2.47 real 2.40 user 0.05 sys
Run Code Online (Sandbox Code Playgroud)
编辑 4:用 C 语言替换 istream 操作符的主体>>
这个版本非常接近 C 的性能:
inline istream &operator>>(istream &in, point &p) {
char buf[1024];
in.getline(buf, 1024);
char *s = strtok(buf, " ");
if (s)
p.x = atof(s);
else
return in;
s = strtok(NULL, " ");
if (s)
p.y = atof(s);
return in;
}
Run Code Online (Sandbox Code Playgroud)
计时未优化让我们进入 2 秒区域,优化将其置于未优化的 C 之上(尽管优化的 C 仍然获胜)。准确地说,没有优化:
2.13 real 2.08 user 0.04 sys
2.14 real 2.07 user 0.04 sys
2.33 real 2.15 user 0.05 sys
2.16 real 2.10 user 0.04 sys
2.18 real 2.12 user 0.04 sys
2.33 real 2.17 user 0.06 sys
Run Code Online (Sandbox Code Playgroud)
和:
1.16 real 1.10 user 0.04 sys
1.19 real 1.13 user 0.04 sys
1.11 real 1.06 user 0.03 sys
1.15 real 1.09 user 0.04 sys
1.14 real 1.09 user 0.04 sys
Run Code Online (Sandbox Code Playgroud)
带有优化的 C,只是为了做apples-to-apples:
0.81 real 0.77 user 0.03 sys
0.82 real 0.78 user 0.04 sys
0.87 real 0.80 user 0.04 sys
0.84 real 0.77 user 0.04 sys
0.83 real 0.78 user 0.04 sys
0.83 real 0.77 user 0.04 sys
Run Code Online (Sandbox Code Playgroud)
我想我可以接受这个,但作为一个 C++ 新手用户,我现在想知道是否:
编辑 5:这个问题与关于 printf 的答案完全不同,我不明白链接的问题这应该是如何解决直接在此之上的三个点中的任何一个的重复。
导致性能显着差异的原因是整体功能的显着差异。
我将尽力详细比较这两种看似相同的方法。
在C中:
循环播放
在 C++ 中:
循环播放
我建议的一种提高性能的方法与彼得在上述评论中所说的非常接近。使用getlineinsideoperator>>以便您可以讲述您的数据。像这样的东西应该能够恢复一些速度,认为它在某种程度上就像C-ing代码的一部分一样:
istream &operator>>(istream &in, point &p) {
char bufX[10], bufY[10];
in.getline(bufX, sizeof(bufX), ' ');
in.getline(bufY, sizeof(bufY), '\n');
p.x = atof(bufX);
p.y = atof(bufY);
return in;
}
Run Code Online (Sandbox Code Playgroud)
希望它有帮助。
编辑:应用nneonneo的评论
| 归档时间: |
|
| 查看次数: |
4883 次 |
| 最近记录: |