[英]Parallelizing a Breadth-First Search
我只是自學了一些OpenMP,這可能很愚蠢。 基本上,我正在嘗試並行化c ++中的廣度優先搜索程序,每個節點都需要花費很長時間來處理。 這是一個示例代碼:
queue<node*> q;
q.push(head);
while (!q.empty()) {
qSize = q.size();
for (int i = 0; i < qSize; i++) {
node* currNode = q.front();
q.pop();
doStuff(currNode);
q.push(currNode);
}
}
處理函數doStuff()非常昂貴,我想對其進行並行化。 但是,如果我通過在#pragma omp parallel for
之前將#pragma omp parallel for
並行化for循環,則在運行時會彈出各種奇怪的錯誤。 我猜測原因是這樣q.front()
和q.push()
也將並行化,並且多個線程可能會通過q.front()
獲得相同的節點(因為它們都在任何q.push
之前被處理了) q.push
已處理)。
我該如何解決?
解決方案是使用關鍵部分來保護對隊列的訪問。
queue<node*> q;
q.push(head);
while (!q.empty()) {
qSize = q.size();
#pragma omp parallel for
for (int i = 0; i < qSize; i++) {
node* currNode;
#pragma omp critical
{
currNode = q.front();
q.pop();
}
doStuff(currNode);
#pragma omp critical
q.push(currNode);
}
}
這類似於擁有一個通用的互斥鎖並將其鎖定。
此版本在效率上有一些限制:在for循環結束時,盡管有一些工作處於隊列中,但某些線程可能仍處於空閑狀態。 就處理隊列為空但某些線程仍在計算的情況而言,創建一個只要隊列中有東西就可以使線程連續工作的版本會有些棘手。
根據節點中涉及的數據大小,您可能還會對緩存效果和錯誤共享產生重大的性能影響。 但這無法通過特定示例進行討論。 簡單版本在許多情況下可能會足夠有效,但是獲得最佳性能可能會變得任意復雜。
無論如何,您必須確保doStuff
不會修改任何全局或共享狀態。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.