2010-11-10 3 views
10

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

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

Мой вопрос в том, почему C# компилятор не может сделать код, используя второй как оптимальный, как код с использованием 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 
} 

Update:

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

Я не спрашивал, будет ли код встроен. 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 отличается для вышеуказанных случаев? Что можно сделать, чтобы сделать структуру так быстро, как дважды? Кажется, нет никакой теоретической разницы между двойным и вторым, какова глубокая причина различий, которые я видел?

+1

- это оператор 'implicit' или' + '? –

+0

Возможно, вам будет интересен этот вопрос: http://stackoverflow.com/questions/348853/units-of-measure-in-c-almost – Benjol

+1

Я знаю, что вы используете C#, но вы считали F #? Он построил в статических единицах, проверяя, что это то, что вы, похоже, ищете. См. Http://stackoverflow.com/questions/40845/how-do-f-units-of-measure-work –

ответ

1

C# компилятор не встраивать ничего - ЛТ может сделать это, но не обязан к. Он все равно должен быть много быстро. Я бы, вероятно, удалить неявное преобразование в +, хотя (см использование конструктора ниже) - еще один оператор полистать:

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 для добавления удвоений; он почти нет Работа - где-то, как ваш код вызывает несколько статических методов и конструктор; всегда будет накладные расходы, даже если они включены.

+0

Я обернул «int» в структуру (реализующую фиксированную точку), и когда дрожание вложило код (IMO он должен встроить код более агрессивно), он создал совершенный код сборки. Таким образом, если встроенный, вероятно, нет накладных расходов. – CodesInChaos

4

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

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

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

Для его оптимизации начните с замены struct на class. Это позволит как минимум свести к минимуму количество копий.

+2

... и структуры помогут вам справиться с проблемой. –

+0

Почему вы хотите использовать классы здесь вместо structs? Проблемы с его приложением (гигантское количество операторов и типов) не изменятся, если он будет использовать «класс», но производительность, вероятно, значительно снизится. – CodesInChaos

+0

@CodeInChaos Я никогда не использую 'struct'. Я действительно думаю, что он должен использоваться только с interop. «производительность, вероятно, снизится», почему? объясните пожалуйста. – Andrey

Смежные вопросы