Общедоступные поля когда-нибудь хорошо?

Оператор

Splatting Для создания массива мы создаем переменную и присваиваем массив. Массивы отмечены символ. Давайте возьмем обсуждение выше и давайте использовать массив для соединения с несколькими удаленными компьютерами:

$strComputers = @("Server1", "Server2", "Server3")

Они используются для массивов и хешей.

Учебное руководство 7 PowerShell: Накопитесь, Отзыв, и Измените Данные

Литералы массивов В PowerShell

22
задан MKing 11 September 2009 в 12:45
поделиться

11 ответов

Ваш тест не совсем справедлив по отношению к версиям на основе свойств. JIT достаточно умен, чтобы встраивать простые свойства, так что они имеют производительность во время выполнения, эквивалентную производительности прямого доступа к полю, но она не кажется достаточно умной (сегодня), чтобы определять, когда свойства обращаются к постоянным значениям.

В вашем примере , все тело цикла версии доступа к полю будет оптимизировано и станет просто:

for (int i = 0; i < loopCount; i++)
00000025  xor         eax,eax 
00000027  inc         eax  
00000028  cmp         eax,989680h 
0000002d  jl          00000027 
}

, тогда как вторая версия фактически выполняет деление с плавающей запятой на каждой итерации:

for (int i = 0; i < loopCount; i++)
00000094  xor         eax,eax 
00000096  fld         dword ptr ds:[01300210h] 
0000009c  fdiv        qword ptr ds:[01300218h] 
000000a2  fstp        st(0) 
000000a4  inc         eax  
000000a5  cmp         eax,989680h 
000000aa  jl          00000096 
}

Внесение всего двух небольших изменений в ваше приложение, чтобы сделать его более реалистично делает две операции практически идентичными по производительности.

Во-первых, рандомизируйте входные значения, чтобы они не были константами, и JIT не достаточно умен, чтобы полностью удалить разделение.

Изменить с:

Point point = new Point(12.0, 123.5, 0.123);

кому:

Random r = new Random();
Point point = new Point(r.NextDouble(), r.NextDouble(), r.NextDouble());

Во-вторых, убедитесь, что где-то используются результаты каждой итерации цикла:

Перед каждым циклом установите значение CalculatedValue = 0, чтобы они оба начинались с одной и той же точки. После каждого цикла вызывайте Console.WriteLine (calculateValue.ToString ()), чтобы убедиться, что результат «используется» и компилятор не оптимизирует его. Наконец, измените тело цикла с «CalculatedValue = ...» на «CalculatedValue + = ...», чтобы использовалась каждая итерация.

На моей машине эти изменения (с релизной сборкой) приводят к следующему результаты:

Direct field access: 133
Property access: 133
Total difference: 0
Average difference: 0

Как и ожидалось, x86 для каждого из этих измененных циклов идентичен (за исключением адреса цикла)

000000dd  xor         eax,eax 
000000df  fld         qword ptr [esp+20h] 
000000e3  fmul        qword ptr [esp+28h] 
000000e7  fdiv        qword ptr [esp+30h] 
000000eb  fstp        st(0) 
000000ed  inc         eax  
000000ee  cmp         eax,989680h 
000000f3  jl          000000DF (This loop address is the only difference) 
31
ответ дан 29 November 2019 в 03:35
поделиться

Возможно, я повторю кого-нибудь еще, но вот моя точка зрения, если это может помочь.

Учения должны предоставить вам инструменты, необходимые для достижения определенного уровня простоты при столкновении с такими ситуациями.

Методология гибкой разработки программного обеспечения гласит, что вы должны сначала доставить продукт своему клиенту, независимо от того, как может выглядеть ваш код. Во-вторых, вы можете оптимизировать и сделать свой код «красивым» или в соответствии с современным уровнем программирования.

Здесь производительность требуется либо вам, либо вашему клиенту. В рамках вашего проекта ПРОИЗВОДИТЕЛЬНОСТЬ ЧРЕЗВЫЧАЙНО, если я правильно понимаю.

Итак, я думаю, вы согласитесь со мной, что нас не волнует, как может выглядеть код или соблюдает ли он «искусство». Делайте все возможное, чтобы сделать его производительным и мощным! Свойства позволяют вашему коду «форматировать» ввод / вывод данных, если это необходимо. У свойства есть собственный адрес в памяти, затем оно ищет адрес своего члена, когда вы возвращаете значение члена, поэтому вы получили два запроса адреса. Если производительность так важна, просто сделайте это и сделайте своих неизменяемых членов общедоступными. : -)

Это отражает и некоторые другие точки зрения, если я правильно прочитал. :)

Хорошего дня!

если я правильно прочитал. :)

Хорошего дня!

если я правильно прочитал. :)

Хорошего дня!

0
ответ дан 29 November 2019 в 03:35
поделиться

Попробуйте скомпилировать сборку выпуска и запустить ее непосредственно из exe, а не через отладчик. Если приложение запускалось через отладчик, JIT-компилятор не будет встроить средства доступа к свойствам. Мне не удалось воспроизвести ваши результаты. Фактически, каждый проведенный мной тест показал, что практически не было разницы во времени выполнения.

Но, как и другие, я не полностью против прямого доступа к полю. Тем более, что легко сделать поле частным и добавить средство доступа к общему свойству позже без необходимости вносить какие-либо изменения в код для компиляции приложения.

Изменить: Хорошо, в моих первоначальных тестах использовалось int тип данных вместо double. Я вижу огромную разницу при использовании дублеров. В случае ints прямое и собственное практически то же самое. С двойным доступом к свойствам доступ примерно в 7 раз медленнее, чем прямой доступ на моей машине. Для меня это несколько озадачивает.

Также важно запускать тесты вне отладчика. Даже в выпускных сборках отладчик добавляет накладные расходы, которые искажают результаты.

При использовании doubles доступ к свойствам примерно в 7 раз медленнее, чем прямой доступ на моей машине. Для меня это несколько озадачивает.

Также важно запускать тесты вне отладчика. Даже в выпускных сборках отладчик добавляет накладные расходы, которые искажают результаты.

При использовании doubles доступ к свойствам примерно в 7 раз медленнее, чем прямой доступ на моей машине. Для меня это несколько озадачивает.

Также важно запускать тесты вне отладчика. Даже в выпускных сборках отладчик добавляет накладные расходы, что искажает результаты.

1
ответ дан 29 November 2019 в 03:35
поделиться

Не то чтобы я не согласен с другими ответами или с вашим выводом ... но я хотел бы знать, откуда вы берете статистику разницы в производительности по порядку величины. Насколько я понимаю компилятор C #, любое свойство simple (без дополнительного кода, кроме прямого доступа к полю) в любом случае должно быть встроено JIT-компилятором как прямой доступ.

Преимущество использования properties даже в этих простых случаях (в большинстве ситуаций) заключалась в том, что, записывая его как свойство, вы допускаете будущие изменения, которые могут изменить свойство. (Хотя в вашем случае, конечно, в будущем таких изменений не будет)

1
ответ дан 29 November 2019 в 03:35
поделиться

Here's some scenarios where it is OK (from the Framework Design Guidelines book):

  • DO use constant fields for constants это никогда не изменится.
  • ОБЯЗАТЕЛЬНО использовать общедоступные статические поля только для чтения для предопределенных экземпляры объектов.

А где это не так:

  • НЕ присваивайте экземпляры изменяемых типы для полей только для чтения.

Из того, что вы сказали, я не понимаю, почему ваши тривиальные свойства не вставляются JIT?

0
ответ дан 29 November 2019 в 03:35
поделиться

If you really need that extra performance, then it's probably the right thing to do. If you don't need the extra performance then it's probably not.

Rico Mariani has a couple of related posts:

3
ответ дан 29 November 2019 в 03:35
поделиться

I know you feel kind of dirty doing this, but it isn't uncommon for rules and guidelines to get shot to hell when performance becomes an issue. For example, quite a few high traffic websites using MySQL have data duplication and denormalized tables. Others go even crazier.

Moral of the story - it may go against everything you were taught or advised, but the benchmarks don't lie. If it works better, just do it.

3
ответ дан 29 November 2019 в 03:35
поделиться

Учитывая, что вы имеете дело с неизменяемыми объектами с полями только для чтения, я бы сказал, что вы попали в тот случай, когда я не считаю общедоступные поля грязной привычкой.

21
ответ дан 29 November 2019 в 03:35
поделиться

IMO, the "no public fields" rule is one of those rules which are technically correct, but unless you are designing a library intended to be used by the public it is unlikely to cause you any problem if you break it.

Before I get too massively downvoted, I should add that encapsulation is a good thing. Given the invariant "the Value property must be null if HasValue is false", this design is flawed:

class A {
    public bool HasValue;
    public object Value;
}

However, given that invariant, this design is equally flawed:

class A {
    public bool HasValue { get; set; }
    public object Value { get; set; }
}

The correct design is

class A {
    public bool HasValue { get; private set; }
    public object Value { get; private set; }

    public void SetValue(bool hasValue, object value) {
        if (!hasValue && value != null)
            throw new ArgumentException();
        this.HasValue = hasValue;
        this.Value    = value;
    }
}

(and even better would be to provide an initializing constructor and make the class immutable).

10
ответ дан 29 November 2019 в 03:35
поделиться

Personally, the only time I would consider using public fields is in a very implementation-specific private nested class.

Other times it just feels too "wrong" to do it.

The CLR will take care of performance by optimising out the method/property (in release builds) so that shouldn't be an issue.

1
ответ дан 29 November 2019 в 03:35
поделиться

If you modify your test to use the temp variables you assign rather than directly access the properties in your calculation you will see a large performance improvement:

        sw.Start();
        for (int i = 0; i < loopCount; i++)
        {
            x = point._x;
            y = point._y;
            z = point._z;
            calculatedValue = x * y / z;
        }
        sw.Stop();
        double fieldTime = sw.ElapsedMilliseconds;
        Console.WriteLine("Direct field access: " + fieldTime);

        sw.Reset();
        sw.Start();
        for (int i = 0; i < loopCount; i++)
        {
            x = point.X;
            y = point.Y;
            z = point.Z;
            calculatedValue = x * y / z;
        }
        sw.Stop();
0
ответ дан 29 November 2019 в 03:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: