使用C#类型表示度量单位

Ily*_*lya 11 c# performance struct operator-keyword

我试图通过将double包装到struct中来获得我称之为测量单位系统的东西.我有C#结构,如Meter,Second,Degree等.我最初的想法是,在编译器内联所有内容后,我将获得与使用double时相同的性能.

我的显式和隐式运算符简单明了,编译器实际上内联它们,但是Meter和Second的代码比使用double的相同代码慢10倍.

我的问题是:为什么C#编译器不能使用Second作为使用double的代码的最佳代码,如果它无论如何都要内联?

第二个定义如下:

struct Second
{
    double _value; // no more fields.

    public static Second operator + (Second left, Second right) 
    { 
        return left._value + right._value; 
    }
    public static implicit Second operator (double value) 
    { 
        // This seems to be faster than having constructor :)
        return new Second { _value = value };
    }

    // plenty of similar operators
}
Run Code Online (Sandbox Code Playgroud)

更新:

我没有问结构是否适合这里.确实如此.

我没有询问代码是否会被内联.JIT确实内联它.

我检查了运行时发出的汇编操作.对于像这样的代码,它们是不同的:

var x = new double();
for (var i = 0; i < 1000000; i++)
{ 
    x = x + 2;
    // Many other simple operator calls here
}
Run Code Online (Sandbox Code Playgroud)

和这样:

var x = new Second();
for (var i = 0; i < 1000000; i++)
{ 
    x = x + 2;
    // Many other simple operator calls here
}
Run Code Online (Sandbox Code Playgroud)

在反汇编中没有调用指令,因此操作实际上是内联的.然而,差异很大.性能测试表明,使用Second比使用double慢10倍.

所以我的问题是(注意!):为什么JIT生成的IA64代码对于上述情况有所不同?如何使struct运行速度与double一样快?似乎双重和第二之间没有理论上的差异,我看到差异的深层原因是什么?

Mar*_*ell 1

C# 编译器不会内联任何内容- JIT可能会这样做,但没有义务这样做。但它应该仍然足够快。我可能会删除其中的隐式转换+(请参阅下面的构造函数用法) - 还要查看另一个运算符:

private readonly double _value;
public double Value { get { return _value; } }
public Second(double value) { this._value = value; }
public static Second operator +(Second left, Second right) {
    return new Second(left._value + right._value);
}
public static implicit operator Second(double value)  {
    return new Second(value);
}
Run Code Online (Sandbox Code Playgroud)

JIT内联仅限于特定场景。这段代码会让他们满意吗?很难说 - 但对于大多数情况来说它应该可以工作并且工作得足够快。问题+是有一个用于添加双精度数的 IL 操作码;它几乎没有任何作用 - 当你的代码调用一些静态方法和构造函数时;即使是内联的,总会有一些开销。