0

我正在尝试并行化 Gauss-Seidel 算法中使用的一些代码,以近似线性方程组的解。

简而言之,对于一个NxN矩阵,在一次迭代期间,我正在sqrt(N)一个接一个地进行并行计算。在并行计算的一个会话中,我将计算sqrt(N)向量值的任务分配给可用的工作人员。

并行计算会话中涉及的代码是这样的:

future_results(1:num_workers) = parallel.FevalFuture;
for i = 1:num_workers
    start_itv = buck_bound+1 + (i - 1) * worker_length;
    end_itv = min(buck_bound+1 + i * worker_length - 1, ends_of_buckets(current_bucket));                 
    future_results(i) = parfeval(p, @hybrid_parallel_function, 3, A, b, x, x_last, buck_bound, n, start_itv, end_itv);
end
            
for i = 1:num_workers
    [~, arr, start_itv, end_itv] = fetchNext(future_results(i));               
    x(start_itv:end_itv) = arr;
end

调用的函数parfeval是这样的:

function [x_par, start_itv, end_itv] = hybrid_parallel_function (A, b, x, x_last, buck_bound, n, start_itv, end_itv)
    x_par = zeros(end_itv - start_itv + 1, 1);
    for i = start_itv:end_itv
        x_par(i-start_itv+1) = b(i);
        x_par(i-start_itv+1) = x_par(i-start_itv+1) - A(i, 1:buck_bound) * x(1:buck_bound);
        x_par(i-start_itv+1) = x_par(i-start_itv+1) - A(i, buck_bound+1:i-1) * x_last(buck_bound+1:i-1);
        x_par(i-start_itv+1) = x_par(i-start_itv+1) - A(i, i+1:n) * x_last(i+1:n);
        x_par(i-start_itv+1) = x_par(i-start_itv+1) / A(i, i);
    end
end

完整的代码可以在这里找到:https ://pastebin.com/hRQ5Ugqz

用于 1000x1000 矩阵的 matlab 分析器。

1000x1000矩阵的 matlab 分析器。并行代码比串行代码慢 20 到 135 倍,具体取决于所选的系数矩阵(并且仍然比 快得多spmd)。

parfeval 计算可能会懒惰地在第 50 行和第 57 行之间拆分?尽管如此,我还是无法向自己解释为什么会有这么大的开销。这似乎与调用 parfeval 的次数有关:我确实通过降低 parfeval 调用来降低执行时间。

有什么可以进一步优化的吗?我必须求助于用 C++ 编写代码吗?

请帮忙。非常感谢!

4

1 回答 1

2

这里有几种可能性。最重要的是一个简单的事实,即如果您使用'local'集群类型,那么工作程序将在单线程代码中运行。在“串行”代码实际上利用 MATLAB 的内在多线程的情况下,您已经充分利用了可用的 CPU 硬件,而使用并行工作器无法为您带来任何好处。不确定您是否属于这种情况,但鉴于代码,我强烈怀疑它。

并行运行会产生开销,正如您所观察到的,运行较少的parfeval调用会降低这些开销。您编写的代码将整个A矩阵多次复制到每个工作人员。你不需要改变A,所以你可以parallel.pool.Constant用来避免那些重复的副本。

虽然parfeval更灵活,但它的效率往往低于可以应用parfor的情况。parfor

parfeval是的,您可以期望工人在第一次通话完成后立即开始工作。

(抱歉,这不是一个真正的“答案”,所以可能会有好心人出现并很快将其删除,但评论内容太多了)。

于 2021-04-12T11:01:05.250 回答