为什么我的模板元代码比 for 循环慢
Why is my template meta code slower than a for loop?
我正在尝试将位置n
中的所有元素汇总为一组std::array
。总和的值存储在传递给我的函数add_rows
的std::array
中。求和是通过递归"调用"模板化类方法来对列的索引递减的列求和来完成的,直到我点击第 0 列,下一行也是如此,直到我点击第 0 行。
还有一个循环版本,它做同样的事情,我比较了执行两种计算总和的方式所需的时间。我希望看到模板化版本性能更好,但它的输出速度慢了~25倍。模板化版本有什么问题,让它变慢吗?
在开始之前,我受到了这篇文章"使用元程序展开循环"的启发
该程序的输出是:
Templated version took: 23 ns.
Loop version took: 0 ns.
法典:
#include <iostream>
#include <array>
#include <numeric>
#include <chrono>
template<size_t num_rows, size_t row_index, size_t num_columns, size_t column_index>
class sumRow;
template<size_t num_rows, size_t row_index, size_t num_columns>
class sumRow<num_rows, row_index, num_columns, 0>
{
public:
static inline int result(const std::array<std::array<int, num_rows>, num_columns>& arrays) noexcept
{
return arrays[0][row_index];
}
};
template<size_t num_rows, size_t row_index, size_t num_columns, size_t column_index>
class sumRow
{
public:
static inline int result(const std::array<std::array<int, num_rows>, num_columns>& arrays) noexcept
{
return arrays[column_index][row_index] + sumRow<num_rows, row_index, num_columns, column_index - 1>::result(arrays);
}
};
// Array of arrays
template<size_t num_rows, size_t row_index, size_t num_columns>
class sumRows;
template<size_t num_rows, size_t num_columns>
class sumRows<num_rows, 0, num_columns>
{
public:
static inline void result(const std::array<std::array<int, num_rows>, num_columns>& arrays, std::array<int, num_rows>& result) noexcept
{
result[0] = sumRow<num_rows, 0, num_columns, num_columns - 1>::result(arrays);
}
};
template<size_t num_rows, size_t row_index, size_t num_columns>
class sumRows
{
public:
static inline void result(const std::array<std::array<int, num_rows>, num_columns>& arrays, std::array<int, num_rows>& result) noexcept
{
result[row_index - 1] = sumRow<num_rows, row_index - 1, num_columns, num_columns - 1>::result(arrays);
sumRows<num_rows, row_index - 1, num_columns>::result(arrays, result);
}
};
template<size_t num_rows, size_t num_columns>
inline void sum_rows(const std::array<std::array<int, num_rows>, num_columns>& arrays, std::array<int, num_rows>& result)
{
sumRows<num_rows, num_rows, num_columns>::result(arrays, result);
};
template<size_t num_channels, size_t channel_size>
inline void loop_sum(const std::array<std::array<int, channel_size>, num_channels>& channels, std::array<int, channel_size>& results) noexcept
{
for (size_t sample_index = 0; sample_index < channel_size; ++sample_index)
{
int result = 0;
for (size_t channel_index = 0; channel_index < num_channels; ++channel_index)
{
result += channels[channel_index][sample_index];
}
results[sample_index] = result;
}
};
// Inspired by from https://stackoverflow.com/a/21995693/2996272
struct measure_cpu_clock
{
template<typename F, typename ...Args>
static clock_t execution(F&& func, Args&&... args)
{
auto start = std::clock();
std::forward<decltype(func)>(func)(std::forward<Args>(args)...);
return std::clock() - start;
}
};
const int num_channels = 850;
const int num_samples = 32;
using channel = std::array<int, num_samples>;
int main()
{
std::array<channel, num_channels> channels{};
for (auto&& item : channels)
{
std::iota(item.begin(), item.end(), 1);
}
// Templated version
channel results = {};
auto execution_time = measure_cpu_clock::execution(sum_rows<num_samples, num_channels>, channels, results);
std::cout << "Templated version took: " << execution_time << " ns." << std::endl;
// Loop version
channel results2 = {};
execution_time = measure_cpu_clock::execution(loop_sum<num_channels, num_samples>, channels, results2);
std::cout << "Loop version took: " << execution_time << " ns." << std::endl;
}
阅读上面的评论后,我添加了一个循环,该循环执行 10000 次总和,并在每次迭代后打印出来。
然后,在每次迭代之前,也要用随机值初始化要求和的数组,现在时间测量表明这两种方法的速度几乎相等(两种方法都有~15个时钟(。
#include <iostream>
#include <array>
#include <numeric>
#include <chrono>
#include <functional>
#include <random>
template<size_t num_rows, size_t row_index, size_t num_columns, size_t column_index>
class sumRow;
template<size_t num_rows, size_t row_index, size_t num_columns>
class sumRow<num_rows, row_index, num_columns, 0>
{
public:
static inline int result(const std::array<std::array<int, num_rows>, num_columns>& arrays) noexcept
{
return arrays[0][row_index];
}
};
template<size_t num_rows, size_t row_index, size_t num_columns, size_t column_index>
class sumRow
{
public:
static inline int result(const std::array<std::array<int, num_rows>, num_columns>& arrays) noexcept
{
return arrays[column_index][row_index] + sumRow<num_rows, row_index, num_columns, column_index - 1>::result(arrays);
}
};
// Array of arrays
template<size_t num_rows, size_t row_index, size_t num_columns>
class sumRows;
template<size_t num_rows, size_t num_columns>
class sumRows<num_rows, 0, num_columns>
{
public:
static inline void result(const std::array<std::array<int, num_rows>, num_columns>& arrays, std::array<int, num_rows>& result) noexcept
{
result[0] = sumRow<num_rows, 0, num_columns, num_columns - 1>::result(arrays);
}
};
template<size_t num_rows, size_t row_index, size_t num_columns>
class sumRows
{
public:
static inline void result(const std::array<std::array<int, num_rows>, num_columns>& arrays, std::array<int, num_rows>& result) noexcept
{
result[row_index - 1] = sumRow<num_rows, row_index - 1, num_columns, num_columns - 1>::result(arrays);
sumRows<num_rows, row_index - 1, num_columns>::result(arrays, result);
}
};
template<size_t num_rows, size_t num_columns>
inline void sum_rows(const std::array<std::array<int, num_rows>, num_columns>& arrays, std::array<int, num_rows>& result)
{
sumRows<num_rows, num_rows, num_columns>::result(arrays, result);
};
template<size_t channel_size, size_t num_channels>
inline void loop_sum(const std::array<std::array<int, channel_size>, num_channels>& channels, std::array<int, channel_size>& results) noexcept
{
for (size_t sample_index = 0; sample_index < channel_size; ++sample_index)
{
int result = 0;
for (size_t channel_index = 0; channel_index < num_channels; ++channel_index)
{
result += channels[channel_index][sample_index];
}
results[sample_index] = result;
}
};
// Inspired by from https://stackoverflow.com/a/21995693/2996272
struct measure_cpu_clock
{
template<typename F, typename ...Args>
static clock_t execution(F&& func, Args&&... args)
{
auto start = std::clock();
std::forward<decltype(func)>(func)(std::forward<Args>(args)...);
return std::clock() - start;
}
};
template<typename T>
T get_random_int(T min, T max)
{
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution <T> dis(min, max);
return dis(gen);
}
template<size_t num_values>
void print_values(std::array<int, num_values>& array)
{
for (auto&& item : array)
{
std::cout << item << "<";
}
std::cout << std::endl;
}
const int num_columns = 850;
const int num_rows = 32;
using channel = std::array<int, num_rows>;
using func = std::function<void(const std::array<std::array<int, num_rows>, num_columns>&, std::array<int, num_rows>&)>;
clock_t perform_many(const func& f)
{
clock_t total_execution_time = 0;
int num_iterations = 10000;
for (int i = 0; i < num_iterations; ++i)
{
std::array<channel, num_columns> channels{};
for (auto&& item : channels)
{
std::iota(item.begin(), item.end(), get_random_int(0, 3));
}
channel results = {};
auto start = std::clock();
f(channels, results);
total_execution_time += (std::clock() - start);
print_values(results);
}
return total_execution_time / num_iterations;
}
int main()
{
// Templated version
auto template_execution_time = perform_many(sum_rows<num_rows, num_columns>);
auto loop_execution_time = perform_many(loop_sum<num_rows, num_columns>);
std::cout << "Templated version took: " << template_execution_time << " clocks" << std::endl;
std::cout << "Loop version took: " << loop_execution_time << " clock" << std::endl;
}
相关文章:
- 如何在C++中从两个单独的for循环中添加两个数组
- 为什么我的for循环不能正确获取argv
- 在基于范围的for循环中使用结构化绑定声明
- 通过for循环使用用户输入填充列表
- 使用for循环检查数组中的重复项
- 在for循环中使用auto vs decltype(vec.size())来处理字符串的向量
- 为什么 const std::p air<K,V>& 在 std::map 上基于范围的 for 循环不起作用?
- 正在使用for循环创建QScatterSerie
- Python中的for循环与C++有何不同
- 在更改for循环的第三部分后,未使用for循环结果
- 在 for 循环中查找问题时遇到困难
- 嵌套for循环C++的问题(初学者)
- 如何用for循环在c++中生成单词三角形
- 如何在for循环中包含两个索引值的测试条件
- 带有多个独立参数的C++For循环
- 为什么我的程序在for循环中k=0时返回垃圾值
- 如何通过替换顺序代码的while循环来添加OpenMP for循环
- C++-For循环未执行
- 基于范围的 for 循环:迭代使用一个元素扩展的向量
- C++ 无法在字符数组中使用 for 循环打印字母模式