gpt4 book ai didi

c++ - 为什么这段代码使用不同的参数传递策略没有显着的性能差异?

转载 作者:行者123 更新时间:2023-11-28 06:17:50 26 4
gpt4 key购买 nike

我正在尝试编写一些代码并说服自己按值传递按引用传递(rvalue lvalue reference)应该对性能有显着影响(related question)。后来我想出了下面这段代码,我认为性能差异应该是可见的。

#include <iostream>
#include <vector>
#include <chrono>

#define DurationTy std::chrono::duration_cast<std::chrono::milliseconds>
typedef std::vector<int> VectTy;
size_t const MAX = 10000u;
size_t const NUM = MAX / 10;

int randomize(int mod) { return std::rand() % mod; }

VectTy factory(size_t size, bool pos) {
VectTy vect;
if (pos) {
for (size_t i = 0u; i < size; i++) {
// vect.push_back(randomize(size));
vect.push_back(i);
}
} else {
for (size_t i = 0u; i < size * 2; i++) {
vect.push_back(i);
// vect.push_back(randomize(size));
}
}
return vect;
}

long d1(VectTy vect) {
long sum = 0;
for (auto& v : vect) sum += v;
return sum;
}

long d2(VectTy& vect) {
long sum = 0;
for (auto& v : vect) sum += v;
return sum;
}

long d3(VectTy&& vect) {
long sum = 0;
for (auto& v : vect) sum += v;
return sum;
}

int main(void) {
{
auto start = std::chrono::steady_clock::now();
long total = 0;
for (size_t i = 0; i < NUM; ++i) {
total += d1(factory(MAX, i % 2)); // T1
}
auto end = std::chrono::steady_clock::now();
std::cout << total << std::endl;
auto elapsed = DurationTy(end - start);
std::cerr << elapsed.count() << std::endl;
}
{
auto start = std::chrono::steady_clock::now();
long total = 0;
for (size_t i = 0; i < NUM; ++i) {
VectTy vect = factory(MAX, i % 2); // T2
total += d1(vect);
}
auto end = std::chrono::steady_clock::now();
std::cout << total << std::endl;
auto elapsed = DurationTy(end - start);
std::cerr << elapsed.count() << std::endl;
}
{
auto start = std::chrono::steady_clock::now();
long total = 0;
for (size_t i = 0; i < NUM; ++i) {
VectTy vect = factory(MAX, i % 2); // T3
total += d2(vect);
}
auto end = std::chrono::steady_clock::now();
std::cout << total << std::endl;
auto elapsed = DurationTy(end - start);
std::cerr << elapsed.count() << std::endl;
}
{
auto start = std::chrono::steady_clock::now();
long total = 0;
for (size_t i = 0; i < NUM; ++i) {
total += d3(factory(MAX, i % 2)); // T4
}
auto end = std::chrono::steady_clock::now();
std::cout << total << std::endl;
auto elapsed = DurationTy(end - start);
std::cerr << elapsed.count() << std::endl;
}
return 0;
}

我在 gcc(4.9.2) 和 clang(trunk) 上用 -std=c++11 选项测试了它。但是我发现在使用clang T2 编译时需要更多时间(一次运行,以毫秒为单位,755,924,752,750)。我还编译了 -fno-elide-constructors 版本,但结果相似。

(更新:使用 Clang 编译时,T1T3T4 存在轻微的性能差异 ( trunk) 在 Mac OS X 上。)

我的问题:

  • 在理论上弥合 T1T2T3 之间潜在性能差距的优化应用是什么? (你可以看到,我在factory中也尽量避免了RVO。)
  • 在这种情况下,gcc 对 T2 应用的可能优化是什么?

最佳答案

这是因为右值引用。您正在按值传递 std::vector - 编译器计算出具有移动构造函数并优化要移动的拷贝。

有关右值引用的详细信息,请参阅以下链接:http://thbecker.net/articles/rvalue_references/section_01.html

更新:以下三种方法是等效的:

在这里,您直接在函数 d1 中传递工厂的返回值,编译器知道返回的值是一个临时值并且 std::vector (VectTy) 有定义了一个移动构造函数 - 它只是调用那个移动构造函数(所以这个函数等同于 d3

long d1(VectTy vect) {
long sum = 0;
for (auto& v : vect) sum += v;
return sum;
}

此处您通过引用传递,因此没有复制 - OTOH,这不应该编译。除非您使用的是 MSVC,否则您应该禁用语言扩展

long d2(VectTy& vect) {
long sum = 0;
for (auto& v : vect) sum += v;
return sum;
}

当然这里不会有任何拷贝,你正在将临时 vector (右值)从工厂移动到d3

long d3(VectTy&& vect) {
long sum = 0;
for (auto& v : vect) sum += v;
return sum;
}

如果您想重现复制性能问题,请尝试推出您自己的 vector 类:

template<class T>
class MyVector
{
private:
std::vector<T> _vec;

public:
MyVector() : _vec()
{}

MyVector(const MyVector& other) : _vec(other._vec)
{}

MyVector& operator=(const MyVector& other)
{
if(this != &other)
this->_vec = other._vec;
return *this;
}

void push_back(T t)
{
this->_vec.push_back(t);
}
};

并使用它代替 std::vector,您肯定会遇到您正在寻找的性能问题

关于c++ - 为什么这段代码使用不同的参数传递策略没有显着的性能差异?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29886594/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com