- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在尝试了解如何提高此 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;
}
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;
}
我喜欢 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
连续多次运行任一程序都不会改变 C++ 版本大约慢 10 倍的结果。
文件格式只是以空格分隔的 double 行,例如:
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
是否有减少我遗漏的开销的技巧?
编辑 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
这并不能真正解决问题。
编辑 2:我正在使用 clang:
$ clang --version
Apple LLVM version 7.0.0 (clang-700.0.72)
Target: x86_64-apple-darwin15.5.0
Thread model: posix
我没有在 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;
}
运行:
$ 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
有趣的是,用 -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
编辑 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;
}
未优化的时间让我们进入了 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
与:
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
经过优化的 C,只是为了做同类:
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
我想我可以接受这个,但作为一个新手 C++ 用户,我现在想知道是否:
编辑 5:这个问题与关于 printf 的答案完全不同,我看不出链接问题 this is supposedly a duplicate of addresses 正上方的三个点中的任何一个。
最佳答案
造成性能显着差异的是整体功能的显着差异。
我会尽我所能详细比较你们这两种看似等效的方法。
在 C 中:
循环
在 C++ 中:
循环
我建议的一种提高性能的方法与 Peter 在上述评论中所说的非常接近。在 operator>>
中使用 getline
,这样您就可以了解您的数据。像这样的东西应该能够让你的速度恢复一些,认为它有点像 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;
}
希望对您有所帮助。
编辑:应用了 nneonneo 的评论
关于C++ iostream 与 C stdio 性能/开销,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37894262/
我想知道,通过数据 channel 发送数据时 WebRTC 会产生多少开销。 我知道 Websockets 每帧有 2 - 14 字节的开销。 WebRTC 是否使用更多开销?我在网上找不到一些有用
我想知道与创建新类而不是该类的新对象相关的开销是小还是大。我正在使用 dojo,但我将提供纯 JS 的示例。我将在启动时创建 10 到 100 个对象,我认为这不会是一个严重的问题,但我想涵盖所有基础
我有一个如下所示的表设置。 Table comment_flags user_id comment_id 我允许用户标记评论,然后给他们取消标记的选项,因为他们可能犯了一个错误。 问题
这个问题已经有答案了: 已关闭10 年前。 Possible Duplicate: In MySQL what does “Overhead” mean, what is bad about it,
我正在制作一个非常简单的游戏,只是为了好玩/练习,但无论它现在有多简单,我仍然想很好地编写它,以防我想回到它并只是为了学习 因此,在这种情况下,我的问题是: 对象分配涉及多少开销?解释器对此的优化程度
我有一些资源敏感的东西要写。我想知道与仅将这些变量一起传递(例如作为函数参数)相比,在结构中将变量组合在一起是否真的会导致内存开销。 如果是这样,那么在不产生开销的情况下创建对惰性值进行操作的东西的好
我一直在开发一个实时应用程序,并注意到一些 OOP 设计模式在 Python 中引入了难以置信的开销(使用 2.7.5 进行了测试)。 直截了当,当字典被另一个对象封装时,为什么简单的字典值访问器方法
我正在从 ifstream 中读取随机 ascii 文本文件。我需要能够将整个消息放入字符串类型以进行字符解析。我当前的解决方案有效,但我认为我通过使用等效于此的方式来谋杀更冗长文件的处理时间: st
纯粹从软件工程的角度来看,getActivity() 有多少开销? 我在整个应用程序中经常多次使用此方法,并考虑使用一个引用 getActivity() 的全局变量。 如果为 Activity 设置一
我一直在研究 Riccardo Terrell 的 Akka.NET 分形演示 (https://github.com/rikace/akkafractal) 以尝试理解它。 (这很棒,顺便说一句)
我正在尝试使用高分辨率计时器查找我的代码运行时间,我注意到计时器的结果不一致,我想知道为什么会这样。 我找到了这篇文章 How do you test running time of VBA code
我正在学习WPF。我现在开始装订了。使用 INotifyPropertyChanged 时绑定(bind)是否依赖反射?是这样,价格是多少?我正在考虑使用 WPF 来显示通过 UDP 流式传输的数据,
我有某种模板化基类 template class Base { }; 并希望将其派生实例存储在列表中。为此,我使用 using derived_handle = std::unique_ptr v
使用GHC.TypeLits中的Sing有任何开销吗? ?以程序为例: {-# LANGUAGE DataKinds #-} module Test (test) where import GHC.T
我有某种模板化基类 template class Base { }; 并希望将其派生实例存储在列表中。为此,我使用 using derived_handle = std::unique_ptr v
我有一个 ORM sqlalchemy 模型,我需要构建一个查询(使用 ORM 类更容易构建),但这需要大量时间。当我直接像 SQL 一样向数据库执行相同的查询时,速度相当快。 使用 SQLAlche
我在 PHP 平台上有一家商店(开发不善),那里有很多不好的查询(没有索引的长查询、rand() 排序、动态计数,..) 我现在无法更改查询,但我必须调整服务器才能保持事件状态。 我尝试了我所知道的一
我有一个使用 JQuery mobile 构建的移动应用程序,响应时间对我来说非常重要,因为我希望为我的用户提供流畅的体验。 我刚刚将网站的安装移至本地服务器,以提高应用程序的性能,因为它连接到本地
关于数据库设计的问题。如果我有 28 个 bool 值并且能够将它们添加为每行 28 个 bool 值或一个整数,哪一个会更快?哪种方法将使磁盘上的表大小保持最低? 这是在假设我需要的可以通过查询中的
我有一个看起来像 Boost.Array 的简单类。有两个模板参数 T 和 N。Boost.Array 的一个缺点是,每个使用这种数组的方法都必须是带有参数 N 的模板(T 可以)。结果是整个程序往往
我是一名优秀的程序员,十分优秀!