【发布时间】:2019-11-19 21:27:59
【问题描述】:
我曾考虑实现一个矩阵类,该类使用算法中的std::transform 进行计算,但我发现在某些情况下编写循环更快。
看看添加operator+= 以进行元素明智的添加。如果 rhs 矩阵有 1 col 而行数与 lhs 矩阵相同,我可以执行以下操作:
for (auto c = 0; c < cols(); ++c) {
std::transform(std::execution::par, col_begin(c), col_end(c), rhs.begin(), col_begin(c), std::plus<>());
}
或使用简单的循环:
auto lhsval = begin();
auto rhsval= rhs.begin();
for (auto r = 0; r < rows(); ++r) {
for (auto c = 0; c < cols(); ++c) {
*lhsval += *rhsval;
++lhsval;
}
++rhsval;
}
为了您的信息,我编写了一个接受步骤的迭代器。所以col_begin() 返回一个迭代器,它将跳过operator++ 中的其他列
我使用 google benchmark 计算了两种实现之间的差异,得出的结论是循环比使用 std::transform 快大约 5 倍。好吧,也许应该有区别,但没有那么大的区别。
您可以在my github repo查看完整代码
【问题讨论】:
-
如果没有
std::execution::par,也会发生同样的事情吗?你是在发布模式下编译吗? -
提示:当询问性能(而不是效率)时,如果不指定如何编译代码,这些问题通常是无法回答的。我们需要 - 您的编译器、您的构建(调试/发布)和您的编译器选项(主要是优化标志)。
-
恕我直言,您在这里遇到了缓存未命中。在第一个示例中,您在两个未连接的内存区域上迭代多次。在第二个中,您只迭代一个具有单个 rhs 值的区域,编译器可以轻松优化该区域
-
@bazz-dee 它一点也不大。缓存未命中(及其子类型,分支错误预测)可能会导致低级别的巨大性能问题。此外,我在您的代码中注意到您的矩阵是如何组织的。难怪在行上迭代然后在列上迭代更快 - 行中的单元格在内存中接近,在一个缓存行中。尝试反转 for 循环并检查性能。我很确定(如果编译器不优化它)它会几乎一样慢
-
您的代码示例看起来并不相同。确保他们做同样的事情。并发布minimal, Complete, and Verifiable example。