Использование типов C # для выражения единиц измерения - PullRequest
11 голосов
/ 10 ноября 2010

Я пытаюсь получить то, что я называю системой единиц измерения, помещая double в struct.У меня есть структуры C #, такие как Meter, Second, Degree и т. Д. Моя оригинальная идея заключалась в том, что после встраивания компилятора все будет иметь такую ​​же производительность, как если бы использовались double.

Мои явные и неявные операторы просты иЭто просто, и компилятор действительно встроил их, но код с Meter и Second в 10 раз медленнее, чем тот же код с использованием double.

Мой вопрос таков: почему компилятор 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
}

Обновление:

Я не спрашивал, подходит ли здесь структура.Это так.

Я не спрашивал, будет ли код встроен.JIT делает это встроенным.

Я проверил операции сборки, выполняемые во время выполнения.Они были разными для такого кода:

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

и так:

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

Не было никаких инструкций вызова при разборке, поэтому операции фактически были встроенными.И все же разница значительна.Тесты производительности показывают, что использование Second примерно в 10 раз медленнее, чем использование double.

Итак, мои вопросы (внимание!): Почему сгенерированный JIT код IA64 отличается для описанных выше случаев?Что можно сделать, чтобы структура работала так же быстро, как в два раза?Кажется, нет никакой теоретической разницы между двойным и вторым, в чем глубокая причина разницы, которую я видел?

Ответы [ 2 ]

4 голосов
/ 10 ноября 2010

Это мое мнение, пожалуйста, напишите комментарий, если вы не согласны, вместо тихого понижения голосов.

C # Компилятор не встроен в него. JIT-компилятор мог бы, но это для нас неопределенно, потому что поведение JITer не простое.

В случае double операторы фактически не вызываются. Операнды добавляются прямо в стек, используя код операции add. В вашем случае вызывается метод op_Add плюс три struct копирования в стек и из него.

Чтобы оптимизировать его, начните с замены struct на class. Это как минимум минимизирует количество копий.

1 голос
/ 10 ноября 2010

Компилятор 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);
}

Встраивание JIT ограничено конкретными сценариями.Удовлетворит ли этот код их?Трудно сказать - но он должен работать и работать достаточно быстро для большинства сценариев.Проблема с + состоит в том, что есть код операции IL для добавления двойников;он почти не работает - где ваш код вызывает несколько статических методов и конструктор;всегда будут некоторые накладные расходы, даже если они встроены.

...