用C++编写性能关键的C#代码

Mik*_*ley 4 c# c++ performance

我目前正在研究一些性能关键代码,我有一个特殊情况,我喜欢用C#编写整个应用程序,但性能原因意味着C++最终会更快地达到FAR.

我对一些代码的两个不同实现进行了一些基准测试(一个用C#编写,另一个用C++编写),时序显示C++版本快了8倍,两个版本都处于发布模式并启用了所有优化.(实际上,C#具有编译为64位的优点.我忘了在C++时序中启用它)

所以我想,我可以在C#中编写大部分代码库(哪个C#非常容易编写),然后编写性能至关重要的本机版本.我在C#和C++中测试的特定代码片段是花费> 95%处理时间的关键领域之一.

这里编写本机代码的推荐智慧是什么?我从来没有写过调用本机C++的C#应用​​程序,所以我不知道该怎么做.我希望以最小化必须尽可能多地执行本机调用的成本的方式执行此操作.

谢谢!

编辑:下面是我实际尝试的大部分代码.这是一个n体仿真.95-99%的CPU时间将用于Body.Pairwise().

class Body
{
    public double Mass;
    public Vector Position;
    public Vector Velocity;
    public Vector Acceleration;

    // snip

    public void Pairwise(Body b)
    {
        Vector dr = b.Position - this.Position;
        double r2 = dr.LengthSq();
        double r3i = 1 / (r2 * Math.Sqrt(r2));

        Vector da = r3i * dr;
        this.Acceleration += (b.Mass * da);
        b.Acceleration -= (this.Mass * da);
    }

    public void Predict(double dt)
    {
        Velocity += (0.5 * dt) * Acceleration;
        Position += dt * Velocity;
    }

    public void Correct(double dt)
    {
        Velocity += (0.5 * dt) * Acceleration;
        Acceleration.Clear();
    }
}
Run Code Online (Sandbox Code Playgroud)

我还有一个只使用以下方法驱动模拟的类:

    public static void Pairwise(Body[] b, int n)
    {
        for (int i = 0; i < n; i++)
            for (int j = i + 1; j < n; j++)
                b[i].Pairwise(b[j]);
    }

    public static void Predict(Body[] b, int n, double dt)
    {
        for (int i = 0; i < n; i++)
            b[i].Predict(dt);
    }

    public static void Correct(Body[] b, int n, double dt)
    {
        for (int i = 0; i < n; i++)
            b[i].Correct(dt);
    }
Run Code Online (Sandbox Code Playgroud)

主循环看起来像:

for (int s = 0; s < steps; s++)
{
    Predict(bodies, n, dt);
    Pairwise(bodies, n);
    Correct(bodies, n, dt);
}
Run Code Online (Sandbox Code Playgroud)

以上只是我实际工作的一个更大的应用程序的最低限度.还有一些事情正在发生,但最重要的性能事件发生在这三个功能中.我知道成对函数很慢(它是n ^ 2),而且我确实有其他方法更快(Barnes-hutt为1,这是n log n)但是这超出了我要求的范围题.

C++代码几乎相同:

struct Body
{
public:
    double Mass;
    Vector Position;
    Vector Velocity;
    Vector Acceleration;

    void Pairwise(Body &b)
    {
        Vector dr = b.Position - this->Position;
        double r2 = dr.LengthSq();
        double r3i = 1 / (r2 * sqrt(r2));

        Vector da = r3i * dr;
        this->Acceleration += (b.Mass * da);
        b.Acceleration -= (this->Mass * da);
    }

    void Predict(double dt)
    {
        Velocity += (0.5 * dt) * Acceleration;
        Position += dt * Velocity;
    }

    void Correct(double dt)
    {
        Velocity += (0.5 * dt) * Acceleration;
        Acceleration.Clear();
    }
};

void Pairwise(Body *b, int n)
{
    for (int i = 0; i < n; i++)
        for (int j = i + 1; j < n; j++)
            b[i].Pairwise(b[j]);
}

void Predict(Body *b, int n, double dt)
{
    for (int i = 0; i < n; i++)
        b[i].Predict(dt);
}

void Correct(Body *b, int n, double dt)
{
    for (int i = 0; i < n; i++)
        b[i].Correct(dt);
}
Run Code Online (Sandbox Code Playgroud)

主循环:

for (int s = 0; s < steps; s++)
{
    Predict(bodies, n, dt);
    Pairwise(bodies, n);
    Correct(bodies, n, dt);
}
Run Code Online (Sandbox Code Playgroud)

还有一个Vector类,它就像一个常规的数学向量一样,为简洁起见,我不包括它.

Han*_*ant 8

您需要与本机代码进行交互.你可以把它放在一个DLL和pinvoke中.好的,当你不经常转换,界面很薄.最灵活,最快速的解决方案是使用C++/CLI语言编写ref类包装器.看看这篇杂志文章的介绍.

最后但并非最不重要的,你真的应该剖析C#代码.8倍是非常过分的.不要开始这个,直到你至少知道为什么这么慢.你不想在C++代码中重现原因,这会毁掉一周的工作.

并提防错误的本能.64位代码是实际速度更快,它通常比x86代码慢一点.它有一堆额外的寄存器非常好.但是所有的指针都是大小的两倍,你不会得到双倍的cpu缓存..