我需要并行化这段代码.如您所见,q数组包含在每个循环中求和的值.

/// <summary>
/// q = A * d, with A stored in CSR format.
/// </summary>
public static double[] Multiplication(int order, double[] d, List<double> A, List<int> J, int[] I)
{ 
    double[] q = new double[order];

    for (int i = 0; i < order; i++)
    {                    
       int indexFirst = I[i];

       q[i] += A[indexFirst] * d[J[indexFirst]];

       for (int j = indexFirst + 1; j < I[i + 1]; j++)
       {
          int col = J[j];
          double a = A[j];

          q[i] += a * d[col];

          q[col] += a * d[i];
       }
   }

   return q;
}

我能够以这种方式并行化代码(将问题分解到CPU计数的区段数中,并最终将得到的q个数组相加),但它似乎过于复杂.有更好的主意吗?

Parallel.For(0, cpuCount, delegate(int i)
{
    MultiplySection(startIndices[i], endIndices[i], d, A, J, I, qSection[i]);
});

double[] q = new double[order];

for (int j = 0; j < cpuCount; j++)
{
    for (int i = startIndices[j]; i < order; i++)
    {
        q[i] += qSection[j][i];
    }
}

private static void MultiplySection(int startIndex, int endIndex, double[] d, List<double> A, List<int> J, int[] I, double[] q)
{
    for (int i = startIndex; i < endIndex; i++)
    {
        int indexFirst = I[i];

        q[i] += A[indexFirst]*d[J[indexFirst]];

        for (int j = indexFirst + 1; j < I[i + 1]; j++)
        {
            int col = J[j];
            double a = A[j];

            q[i] += a*d[col];

            q[col] += a*d[i];
        }
    }
}

推荐答案

您当前的实现是粗粒度的,所以如果一个CPU核心忙于其他事情,那么在您的进程结束时,您可能会遇到利用率较低的风险.

我至少会try 使用内置的并行分区.这应该会提供细粒度的并发性,这可能有助于提高效率.您还可以使用localInit/LocalFinally方法创建和合并数组:

public static double[] Multiplication(int order, double[] d, List<double> A, List<int> J, int[] I)
{
    double[] qTotal = new double[order];

    Parallel.For(0,
        order,
        () => new double[order], // LocalInit
        (i, loopState, q) => // Main Body
        {
            int indexFirst = I[i];

            q[i] += A[indexFirst] * d[J[indexFirst]];

            for (int j = indexFirst + 1; j < I[i + 1]; j++)
            {
                int col = J[j];
                double a = A[j];

                q[i] += a * d[col];

                q[col] += a * d[i];
            }
            return q;
        },
        q => // Local Finally 
        {
            lock (qTotal)
            {
                for (int i = 0; i < q.Length; i++)
                {
                    qTotal[i] += q[i];
                }
            }
        });
    return qTotal;
}

如果循环体中的工作量很小,您仍然可以从批处理中受益,但您可能希望使用固定的批处理大小,而不是基于处理器的数量.这应该会对各种类型的管理费用有所帮助.您可能需要进行一些实验,以找到最佳的批处理大小.

Csharp相关问答推荐

使用变量子根名称在C#中重新初始化SON文件

图形.DrawString奇怪异常的字距调整

MongoDB将JS查询转换为C#的问题

dotnet集合中内部数组的局部变量副本的用途是什么?'

在实时数据库中匹配两个玩家的问题

.NET 8 Web-API返回空列表

C#.NET依赖项注入顺序澄清

将轮询与超时同步

ASP.NET核心MVC SqlException:违反主键约束';PK_USER';.无法在对象';数据库中插入重复的密钥.用户';

在C#中反序列化/序列化具有混合元素顺序的XML时出现问题

当索引和外键是不同的数据类型时,如何设置导航属性?

用于管理System.Text.Json中的多态反序列化的自定义TypeInfoResolver

Swagger没有显示int?可以为空

正在try 从Blazor中的API读取JSON

Blazor Fluent UI DialogService,<;FluentDialogProvider/>;错误

Blazor Server.NET 8中的Blazore.FluentValidation问题

Visual Studio 17.8.0制表符自动完成问题--三缩进

Cmd中的&ping.end()";有时会失败,而";ping";总是有效

无效的Zip文件-Zip存档

如何处理ASP.NET Core中包含两个构造函数的控制器?