C++ for循环效率优化
背景
今天看到同事的代码,commit message说要提高循环效率,但是看起来非常浪费时间,我就想试一下for循环怎么写运行最快,发现还是非常有意思的。
首先是编译选项,在X86系统编译Release,优化等级-O3,关闭gdb
SET(CMAKE_BUILD_TYPE "Release")
SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")
这个循环非常简单,遍历一个结构体的vector,读一下数据执行一些操作,然后写入另一个vector,写一个简单的结构体,定义一下两个vector。
struct A
{
int a;
float b;
};
/* some code */
const int size = 100000000;
vector<A> from(size);
vector<A> to(size);
几种写法
for+push_back
for (size_t i = 0; i < from.size(); i++)
{
a = from[i].a;
b = from[i].b;
to.push_back(from[i]);
}
不解释,耗时0.692793s。
范围for+emplace_back
for (auto f : from)
{
a = f.a;
b = f.b;
to.emplace_back(f);
}
范围for会逐个创建from中元素的拷贝,使用后我们把它移动到新的vector,耗时1.036604s。
临时引用+push_back
for (size_t i = 0; i < from.size(); i++)
{
auto &t = from[i];
a = t.a;
b = t.b;
to.push_back(t);
}
耗时0.351039s。
看起来已经减少了很多时间,还能再减少吗?
临时变量+emplace_back
for (size_t i = 0; i < from.size(); i++)
{
auto t = from[i];
a = t.a;
b = t.b;
to.emplace_back(t);
}
耗时1.801415s。
临时引用+std::copy
接下来是性能优化大杀器std::copy~
for (size_t i = 0; i < from.size(); i++)
{
auto &t = from[i];
a = t.a;
b = t.b;
}
std::copy(from.begin(), from.end(), to.begin());
访问拷贝分离,耗时0.339706s。好像没有很惊艳,接着看。
范围for+std::copy
for (auto &f : from)
{
a = f.a;
b = f.b;
}
std::copy(from.begin(), from.end(), to.begin());
耗时0.076393s。YYDS
std::for_each+std::copy
auto Fun = [&](A &t) { a = t.a; b = t.b; };
std::for_each(from.begin(), from.end(), Fun);
std::copy(from.begin(), from.end(), to.begin());
耗时0.073591s,不分伯仲。
总结
c++程序员永远不知道自己浪费了多少时间,emplace_back表现不好,应该是预分配内存导致没有用武之地,如果是链式结构会好很多。