openmp 增加线程数会增加执行时间

openmp increasing number of threads increases the execution time

我在将稀疏矩阵乘法(元素类型 std::complex)转换为 CSR(压缩稀疏行)格式后实现了它们,我为此使用了 openmp,但我注意到增加线程数并不一定会提高性能,有时恰恰相反!为什么会这样?我该怎么做才能解决这个问题?

typedef std::vector < std::vector < std::complex < int >>> matrix;

struct CSR {
    std::vector<std::complex<int>> values; //non-zero values
    std::vector<int> row_ptr; //pointers of rows
    std::vector<int> cols_index; //indices of columns
    int rows; //number of rows
    int cols; //number of columns
    int NNZ; //number of non_zero elements
};

const matrix multiply_omp (const CSR& A,
    const CSR& B,const unsigned int num_threds=4) {
    if (A.cols != B.rows)
        throw "Error";
    CSR B_t = sparse_transpose(B);
    omp_set_num_threads(num_threds);
    matrix result(A.rows, std::vector < std::complex < int >>(B.cols, 0));
    #pragma omp parallel
    {
        int i, j, k, l;
        #pragma omp for
        for (i = 0; i < A.rows; i++) {
            for (j = 0; j < B_t.rows; j++) {
                std::complex < int > sum(0, 0);
                for (k = A.row_ptr[i]; k < A.row_ptr[i + 1]; k++)
                    for (l = B_t.row_ptr[j]; l < B_t.row_ptr[j + 1]; l++)
                        if (A.cols_index[k] == B_t.cols_index[l]) {
                            sum += A.values[k] * B_t.values[l];
                            break;
                        }
                if (sum != std::complex < int >(0, 0)) {
                    result[i][j] += sum;
                }
            }
        }
    }
    return result;
}

您可以尝试改进此算法的缩放比例,但我会使用更好的算法。您正在为两个稀疏矩阵的乘积分配一个密集矩阵(错误地,但这不是重点)。这很浪费,因为两个稀疏矩阵的投影通常不会很密集。

您的算法的时间复杂度也不对。您搜索 B 的行的方式意味着您的复杂性有一个额外的因素,例如每行的平均非零数。更好的算法会假定每一行中的索引都已排序,然后保留一个指针,指示您进入该行的距离。

阅读有关“Graph Blas”的文献以获取高效算法的参考。