通过编写C dll来加速C#中的数学代码?

Pro*_*ish 12 .net c c# performance

我有一个非常大的嵌套for循环,其中对浮点数执行一些乘法和加法.

for (int i = 0; i < length1; i++)
{
    double aa = 0;
    for(int h = 0; h < 10; h++)
    {
       aa += omega[i][outsideGeneratedAddress[h]];
    }

    double alphaOld = alpha;
    alpha = Math.Sqrt(alpha * alpha + aa * aa);

    s = -aa / alpha;
    c = alphaOld / alpha;

    for(int j = 0; j <= i; j++)
    {
        double oldU = u[j];
        u[j] = c * oldU + s * omega[i][j];
        omega[i][j] = c * omega[i][j] - s * oldU;
    }
}
Run Code Online (Sandbox Code Playgroud)

这个循环占用了我的大部分处理时间,并且是一个瓶颈.

如果我在C中重写这个循环并从C#接口,我是否可能看到任何速度改进?

编辑:我更新了代码,以显示如何生成s和c.内部循环实际上从0到i,尽管它可能对问题没有太大影响

EDIT2:我在VC++中实现了算法并通过dll将其与C#相关联,并且在启用所有优化后,C#的速度提升了28%.启用S​​SE2的参数特别有效.使用MinGW和gcc4.4进行编译只能提高15%的速度.刚尝试了英特尔编译器,该代码的速度提升了49%.

Mit*_*eat 8

更新:

如果你编写内部循环来考虑引用的位置会发生什么:

for (int i = 0; i < length1; i++) 
{ 
    s = GetS(i); 
    c = GetC(i); 
    double[] omegaTemp = omega[i]; 

    for(int j = 0; j < length2; j++) 
    { 
        double oldU = u[j]; 
        u[j] = c * oldU + s * omegaTemp[j]; 
        omegaTemp[j] = c * omegaTemp[j] - s * oldU; 
    } 
} 
Run Code Online (Sandbox Code Playgroud)

  • 如果我没记错的话,如果for循环相对简单,C#编译器也可以优化远程边界检查.米奇的建议可能也启用了此优化.http://blogs.msdn.com/b/clrcodegeneration/archive/2009/08/13/array-bounds-check-elimination-in-the-clr.aspx (4认同)
  • 如果边界检查确实现在正在被优化,我不会期望更好的性能与不安全的代码. (2认同)

Don*_*nie 7

使用unsafe块和指针索引到您的omega数组.这将消除范围检查的开销,如果您进行了足够的访问,则可能是一个重要的胜利.很多时间也可能花在你GetS()GetC()你没有提供源代码的功能上.

  • `fixed`语句在放入循环时往往会减慢速度.诀窍是将数组只修复一次作为最外层语句. (4认同)
  • 您可能希望经常避免进入和退出不安全的上下文,因为它可能具有代码访问安全隐患,例如堆栈遍历以验证权限. (3认同)
  • 您可能想发布一些您编写的不安全代码.没有什么理由会变慢. (2认同)

em7*_*m70 2

虽然大多数其他答案倾向于建议您研究 C# 解决方案,但大多数都忽略了一点:如果您使用良好的优化编译器,此方法的 C 代码会更快(我建议 Intel,对于此类代码非常有效) )。
编译器还将节省一些 JIT 工作,并产生更好的编译输出(甚至 MSVC 编译器也可以生成 SSE2 指令)。默认情况下不会检查数组边界,可能会展开一些循环,总而言之,您可能会看到性能的显着提升。
正如已经正确指出的那样,调用本机代码可能会产生一些开销;然而,如果 length1 足够大,与加速相比,这应该是微不足道的。
您可能肯定会将此代码保留在 C# 中,但请记住,与几个 C 编译器相比,CLR(就像我所知道的所有其他 VM 一样)对优化生成的代码几乎没有作用。