[英]Make Sparse Matrix Multiply Fast
該代碼使用C ++ 11編寫。 每個進程都有兩個矩陣數據(稀疏)。 可以從此處的輸入鏈接描述中下載測試數據
測試數據包含2個文件:a0(稀疏矩陣0)和a1(稀疏矩陣1)。 文件中的每一行都是“ ijv”,表示稀疏矩陣行i,列j的值為v。i,j,v都是整數。
使用c ++ 11 unordered_map作為稀疏矩陣的數據結構。
unordered_map<int, unordered_map<int, double> > matrix1 ;
matrix1[i][j] = v ; //means at row i column j of matrix1 is value v;
以下代碼耗時約2分鍾。 編譯命令是g++ -O2 -std=c++11 ./matmult.cpp
。
g ++版本是4.8.1,Opensuse 13.1。 我的電腦的信息:英特爾®酷睿™i5-4200U CPU @ 1.60GHz,4G內存。
#include <iostream>
#include <fstream>
#include <unordered_map>
#include <vector>
#include <thread>
using namespace std;
void load(string fn, unordered_map<int,unordered_map<int, double> > &m) {
ifstream input ;
input.open(fn);
int i, j ; double v;
while (input >> i >> j >> v) {
m[i][j] = v;
}
}
unordered_map<int,unordered_map<int, double> > m1;
unordered_map<int,unordered_map<int, double> > m2;
//vector<vector<int> > keys(BLK_SIZE);
int main() {
load("./a0",m1);
load("./a1",m2);
for (auto r1 : m1) {
for (auto r2 : m2) {
double sim = 0.0 ;
for (auto c1 : r1.second) {
auto f = r2.second.find(c1.first);
if (f != r2.second.end()) {
sim += (f->second) * (c1.second) ;
}
}
}
}
return 0;
}
上面的代碼太慢了。 如何使其運行更快? 我使用多線程。 新代碼如下,編譯命令為g++ -O2 -std=c++11 -pthread ./test.cpp
。 大約花了1分鍾。 我希望它更快。
如何使任務更快? 謝謝!
#include <iostream>
#include <fstream>
#include <unordered_map>
#include <vector>
#include <thread>
#define BLK_SIZE 8
using namespace std;
void load(string fn, unordered_map<int,unordered_map<int, double> > &m) {
ifstream input ;
input.open(fn);
int i, j ; double v;
while (input >> i >> j >> v) {
m[i][j] = v;
}
}
unordered_map<int,unordered_map<int, double> > m1;
unordered_map<int,unordered_map<int, double> > m2;
vector<vector<int> > keys(BLK_SIZE);
void thread_sim(int blk_id) {
for (auto row1_id : keys[blk_id]) {
auto r1 = m1[row1_id];
for (auto r2p : m2) {
double sim = 0.0;
for (auto col1 : r1) {
auto f = r2p.second.find(col1.first);
if (f != r2p.second.end()) {
sim += (f->second) * col1.second ;
}
}
}
}
}
int main() {
load("./a0",m1);
load("./a1",m2);
int df = BLK_SIZE - (m1.size() % BLK_SIZE);
int blk_rows = (m1.size() + df) / (BLK_SIZE - 1);
int curr_thread_id = 0;
int index = 0;
for (auto k : m1) {
keys[curr_thread_id].push_back(k.first);
index++;
if (index==blk_rows) {
index = 0;
curr_thread_id++;
}
}
cout << "ok" << endl;
std::thread t[BLK_SIZE];
for (int i = 0 ; i < BLK_SIZE ; ++i){
t[i] = std::thread(thread_sim,i);
}
for (int i = 0; i< BLK_SIZE; ++i)
t[i].join();
return 0 ;
}
在大多數情況下,使用稀疏矩陣會比使用嵌套映射使用更有效的表示形式。 典型選擇是壓縮稀疏行(CSR)或壓縮稀疏列(CSC)。 有關詳細信息,請參見https://en.wikipedia.org/wiki/Sparse_matrix 。
您尚未指定示例運行的時間或希望運行平台的時間。 這些是此示例中的重要設計約束。
我可以考慮改善以下幾個方面的效率:-
第一點針對系統存儲稀疏數組和接口以使數據能夠被讀取的方式。 如果速度並不重要,但是可以使用更具體的數據結構來解決此問題,則嵌套的unordered_maps是一個不錯的選擇。 最好的情況是,您可能會找到一個比嵌套地圖提供更好的數據存儲方式的庫,最壞的情況下,您可能必須自己准備一些東西。
第二點涉及該語言支持多線程的方式。 多線程系統的原始規范旨在獨立於平台,並且可能會錯過某些系統可能具有的便捷功能。 確定要定位的系統並使用OS線程系統。 您將對線程的工作方式有更多控制,可能會減少開銷,但會失去跨平台支持。
第三點需要一些工作。 在給定數據性質的情況下,乘矩陣的方法確實是最有效的方法。 我不是這些方面的專家,但是可以考慮,但是需要一些努力。
最后,您始終可以非常清楚自己所運行的平台,並進入匯編程序設計領域。 現代CPU是復雜的野獸。 他們有時可以並行執行操作。 例如,您可以執行SIMD運算或並行整數和浮點運算。 這樣做確實需要對正在發生的事情有深刻的了解,並且有一些有用的工具可以幫助您。 英特爾確實有一個稱為VTune的工具(現在可能是其他名稱),該工具可以分析代碼並突出顯示潛在的瓶頸。 最終,您將想要消除CPU閑置等待某些事情發生的算法區域(例如,等待來自RAM的數據),方法是尋找其他可以讓CPU進行的事情或改進算法(或兩者)。
最終,為了提高整體速度,您需要了解導致速度下降的原因。 這通常意味着知道如何分析代碼並了解結果。 探查器是用於此的通用工具,但也有特定於平台的工具。
我知道這不是您想要的,但是快速編寫代碼確實非常困難且非常耗時。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.