[英]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.