[英]Fastest way to create a vector of indices from distance matrix in C++
我有一个大小为
n
xn
的距离矩阵D
和一个常数L
作为输入。 我需要创建一个向量v
包含D
中的所有条目,使其值最多为L
。 这里v
必须按特定顺序v = [v1 v2.. vn]
其中vi
包含D
的第i
行中的条目,其值最多为L
。 每个vi
中的条目顺序并不重要。
我想知道有没有一种使用向量、数组或任何数据结构 + 并行化创建v
的快速方法。 我所做的是使用 for 循环,对于大n
来说非常慢。
vector<int> v;
for (int i=0; i < n; ++i){
for (int j=0; j < n; ++j){
if (D(i,j) <= L) v.push_back(j);
}
}
考虑到评论,我做了适当的更正(强调)。
您是否搜索过编写性能代码、线程、asm 指令(如果您的程序集不是您想要的)和用于并行处理的 OpenCL 的技巧? 如果没有,我强烈推荐!
在某些情况下,在 for 循环之外声明所有 for 循环变量(以避免多次声明它们)会使其更快,但在这种情况下不会(来自我们的朋友 Paddy 的评论) 。
此外,使用new
插入的vector
可以更快,正如我们在此处看到的: 在 C++ 中使用 arrays 或 std::vectors,性能差距是什么? -我测试了,使用vector
比使用new
慢 6 秒,只需要 1 秒。 我猜想当有人在搜索性能时,不需要 std::vector 带来的安全性和易于管理的保证,即使因为使用new
并不是那么困难,只要避免计算的堆溢出并记住使用delete[]
user4581301 在这里是正确的,下面的说法是不正确的:最后,如果你在一个数组而不是矩阵中构建D
(或者如果你将D
复制到一个常量数组中,也许......),它将会更加缓存友好并将保存一个 for 循环语句。
最好的方法主要取决于上下文。 如果您正在寻找 GPU 并行化,您应该看看 OpenCL。
对于基于 CPU 的并行化,C++ 标准#include <thread>
库可能是您最好的选择,但您需要小心:
v 可能是以 vi 作为其子向量的 2d 向量,但必须在并行化之前对其进行初始化:
std::vector<std::vector<int>> v;
v.reserve(n);
for(size_t i = 0; i < n; i++)
{
v.push_back(std::vector<int>());
}
您需要决定要使用多少线程。 如果这仅适用于一台机器,硬编码是一个有效的选项。 线程库中有一个 function 可以获取支持的线程数量,但它更多的是提示而不是值得信赖。
size_t threadAmount = std::thread::hardware_concurrency(); //How many threads should run hardware_concurrency() gives you a hint, but its not optimal
std::vector<std::thread> t; //to store the threads in
t.reserve(threadAmount-1); //you need threadAmount-1 extra threads (we already have the main-thread)
要启动一个线程,您需要一个可以执行的 function。 在这种情况下,这是通读矩阵的一部分。
void CheckPart(size_t start, size_t amount, int L, std::vector<std::vector<int>>& vec)
{
for(size_t i = start; i < amount+start; i++)
{
for(size_t j = 0; j < n; j++)
{
if(D(i,j) <= L)
{
vec[i].push_back(j);
}
}
}
}
现在您需要将矩阵拆分为大约 n/threadAmount 行的部分并启动线程。 线程构造函数需要一个 function 及其参数,但它总是会尝试复制参数,即使 function 需要一个引用。 为了防止这种情况,您需要强制使用带有std::ref()
的引用
int i = 0;
int rows;
for(size_t a = 0; a < threadAmount-1; a++)
{
rows = n/threadAmount + ((n%threadAmount>a)?1:0);
t.push_back(std::thread(CheckPart, i, rows, L, std::ref(v)));
i += rows;
}
线程现在正在运行,所要做的就是运行主 function 上的最后一个块:
SortPart(i, n/threadAmount, L, v);
之后,您需要等待线程完成并清理它们:
for(unsigned int a = 0; a < threadAmount-1; a++)
{
if(t[a].joinable())
{
t[a].join();
}
}
请注意,这只是一个快速而肮脏的例子。 不同的问题可能需要不同的实现,而且由于我无法猜测上下文,因此我可以提供的帮助非常有限。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.