访问Boost MultiArray中元素的最快方法
Fastest method of accessing elements in Boost MultiArray
使用元素选择操作符访问多数组的元素,还是使用迭代器遍历多数组,哪个更快?
在我的例子中,我需要对multiarray的所有元素进行一次完整的传递。
访问boost::multi_array
的每个元素的最快方法是通过data()
和num_elements()
。
使用data()
,您可以访问底层原始存储(包含数组数据的连续块),因此不需要进行多次索引计算(还要考虑multi_array
可以从不同于0的基数对数组进行索引,这是一个进一步的复杂性)。
一个简单的测试给出:
g++ -O3 -fomit-frame-pointer -march=native (GCC v4.8.2)
Writing (index): 9.70651
Writing (data): 2.22353
Reading (index): 4.5973 (found 1)
Reading (data): 3.53811 (found 1)
clang++ -O3 -fomit-frame-pointer -march=native (CLANG v3.3)
Writing (index): 5.49858
Writing (data): 2.13678
Reading (index): 5.07324 (found 1)
Reading (data): 2.55109 (found 1)
默认情况下,boost访问方法执行范围检查。如果提供的索引超出了为数组定义的范围,则断言将中止程序。要禁用范围检查,您可以在应用程序中包含multi_array.hpp
之前定义BOOST_DISABLE_ASSERTS
预处理器宏。
这将大大减少性能差异:
g++ -O3 -fomit-frame-pointer -march=native (GCC v4.8.2)
Writing (index): 3.15244
Writing (data): 2.23002
Reading (index): 1.89553 (found 1)
Reading (data): 1.54427 (found 1)
clang++ -O3 -fomit-frame-pointer -march=native (CLANG v3.3)
Writing (index): 2.24831
Writing (data): 2.12853
Reading (index): 2.59164 (found 1)
Reading (data): 2.52141 (found 1)
性能差异增加(即data()
更快):
- 具有更高维度数; 元素较少的
- (对于大量元素,对元素的访问并不像将这些元素加载到CPU缓存中的缓存压力那么重要)。预取器将在那里尝试加载这些元素,这将占用很大比例的时间)。
#include <chrono>
#include <iostream>
// #define BOOST_DISABLE_ASSERTS
#include <boost/multi_array.hpp>
int main()
{
using array3 = boost::multi_array<unsigned, 3>;
using index = array3::index;
using clock = std::chrono::high_resolution_clock;
using duration = std::chrono::duration<double>;
constexpr unsigned d1(300), d2(400), d3(200), sup(100);
array3 A(boost::extents[d1][d2][d3]);
// Writing via index
const auto t_begin1(clock::now());
unsigned values1(0);
for (unsigned n(0); n < sup; ++n)
for (index i(0); i != d1; ++i)
for (index j(0); j != d2; ++j)
for (index k(0); k != d3; ++k)
A[i][j][k] = ++values1;
const auto t_end1(clock::now());
// Writing directly
const auto t_begin2(clock::now());
unsigned values2(0);
for (unsigned n(0); n < sup; ++n)
{
const auto sup(A.data() + A.num_elements());
for (auto i(A.data()); i != sup; ++i)
*i = ++values2;
}
const auto t_end2(clock::now());
// Reading via index
const auto t_begin3(clock::now());
bool found1(false);
for (unsigned n(0); n < sup; ++n)
for (index i(0); i != d1; ++i)
for (index j(0); j != d2; ++j)
for (index k(0); k != d3; ++k)
if (A[i][j][k] == values1)
found1 = true;
const auto t_end3(clock::now());
// Reading directly
const auto t_begin4(clock::now());
bool found2(false);
for (unsigned n(0); n < sup; ++n)
{
const auto sup(A.data() + A.num_elements());
for (auto i(A.data()); i != sup; ++i)
if (*i == values2)
found2 = true;
}
const auto t_end4(clock::now());
std::cout << "Writing (index): "
<< std::chrono::duration_cast<duration>(t_end1 - t_begin1).count()
<< std::endl
<< "Writing (data): "
<< std::chrono::duration_cast<duration>(t_end2 - t_begin2).count()
<< std::endl
<< "Reading (index): "
<< std::chrono::duration_cast<duration>(t_end3 - t_begin3).count()
<< " (found " << found1 << ")" << std::endl
<< "Reading (data): "
<< std::chrono::duration_cast<duration>(t_end4 - t_begin4).count()
<< " (found " << found2 << ")" << std::endl;
return 0;
}
相关文章:
- 数组元素打印的递归方法
- 如何实现 Front() 方法以返回模板化双向链表C++的第一个元素?
- 有什么方法可以将元素添加到列表中,如图所示?
- 在向量中查找大于 0(或通常为 k)的最小元素的最佳方法是什么?
- C++将所有元素从矢量复制到地图/unordered_map的最佳方法
- 在C++中更改结构内部元素的方法?
- 通过作为指向 C++ 函数的指针传递来访问 std::array 元素的正确方法是什么?
- 有没有更快的方法可以在 std::vector 中插入元素
- 返回向量元素的 l 值的正确方法是什么?
- 按升序打印矢量的所有元素直到它为空而没有重复项的最有效方法是什么?
- C++去除前x个元素的有效方法,在不改变向量大小的情况下将第x+1个元素推到第一个
- 如何在不迭代的情况下对数组中的每个元素调用方法
- 是否有更有效的方法来检查元素是否在给定的区间内
- 这种获取模板参数包中最后一个元素的方法是否有隐藏的开销?
- 将__m256的奇怪元素提取到__m128中的有效(在锐龙上)方法?
- 为什么 memcpy() 是一种将元素添加到 'std::map' 的方法?
- 从长(且合理)稀疏向量中选择随机元素的最有效方法是什么?
- 如何使用返回第 n 个元素的方法创建元组
- 如何在不使用 vector::erase() 的情况下编写自定义 Vector 方法来删除元素?
- 从任意容器中廉价删除元素的惯用方法?