簡體   English   中英

從 C++ 中的距離矩陣創建索引向量的最快方法

[英]Fastest way to create a vector of indices from distance matrix in C++

我有一個大小為n x n的距離矩陣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>庫可能是您最好的選擇,但您需要小心:

  • 創建線程需要時間,因此如果 n 相對較小(<1000 左右),它會減慢您的速度
  • D(i,j) 必須同時被多個線程讀取
  • v 必須可由多個線程寫入,標准向量不會削減它

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM