Оператор
Splatting Для создания массива мы создаем переменную и присваиваем массив. Массивы отмечены символ. Давайте возьмем обсуждение выше и давайте использовать массив для соединения с несколькими удаленными компьютерами:
$strComputers = @("Server1", "Server2", "Server3")
Они используются для массивов и хешей.
Учебное руководство 7 PowerShell: Накопитесь, Отзыв, и Измените Данные
Ваш тест не совсем справедлив по отношению к версиям на основе свойств. 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)
Возможно, я повторю кого-нибудь еще, но вот моя точка зрения, если это может помочь.
Учения должны предоставить вам инструменты, необходимые для достижения определенного уровня простоты при столкновении с такими ситуациями.
Методология гибкой разработки программного обеспечения гласит, что вы должны сначала доставить продукт своему клиенту, независимо от того, как может выглядеть ваш код. Во-вторых, вы можете оптимизировать и сделать свой код «красивым» или в соответствии с современным уровнем программирования.
Здесь производительность требуется либо вам, либо вашему клиенту. В рамках вашего проекта ПРОИЗВОДИТЕЛЬНОСТЬ ЧРЕЗВЫЧАЙНО, если я правильно понимаю.
Итак, я думаю, вы согласитесь со мной, что нас не волнует, как может выглядеть код или соблюдает ли он «искусство». Делайте все возможное, чтобы сделать его производительным и мощным! Свойства позволяют вашему коду «форматировать» ввод / вывод данных, если это необходимо. У свойства есть собственный адрес в памяти, затем оно ищет адрес своего члена, когда вы возвращаете значение члена, поэтому вы получили два запроса адреса. Если производительность так важна, просто сделайте это и сделайте своих неизменяемых членов общедоступными. : -)
Это отражает и некоторые другие точки зрения, если я правильно прочитал. :)
Хорошего дня!
если я правильно прочитал. :)Хорошего дня!
если я правильно прочитал. :)Хорошего дня!
Попробуйте скомпилировать сборку выпуска и запустить ее непосредственно из exe, а не через отладчик. Если приложение запускалось через отладчик, JIT-компилятор не будет встроить средства доступа к свойствам. Мне не удалось воспроизвести ваши результаты. Фактически, каждый проведенный мной тест показал, что практически не было разницы во времени выполнения.
Но, как и другие, я не полностью против прямого доступа к полю. Тем более, что легко сделать поле частным и добавить средство доступа к общему свойству позже без необходимости вносить какие-либо изменения в код для компиляции приложения.
Изменить: Хорошо, в моих первоначальных тестах использовалось int тип данных вместо double. Я вижу огромную разницу при использовании дублеров. В случае ints прямое и собственное практически то же самое. С двойным доступом к свойствам доступ примерно в 7 раз медленнее, чем прямой доступ на моей машине. Для меня это несколько озадачивает.
Также важно запускать тесты вне отладчика. Даже в выпускных сборках отладчик добавляет накладные расходы, которые искажают результаты.
При использовании doubles доступ к свойствам примерно в 7 раз медленнее, чем прямой доступ на моей машине. Для меня это несколько озадачивает.Также важно запускать тесты вне отладчика. Даже в выпускных сборках отладчик добавляет накладные расходы, которые искажают результаты.
При использовании doubles доступ к свойствам примерно в 7 раз медленнее, чем прямой доступ на моей машине. Для меня это несколько озадачивает.Также важно запускать тесты вне отладчика. Даже в выпускных сборках отладчик добавляет накладные расходы, что искажает результаты.
Не то чтобы я не согласен с другими ответами или с вашим выводом ... но я хотел бы знать, откуда вы берете статистику разницы в производительности по порядку величины. Насколько я понимаю компилятор C #, любое свойство simple (без дополнительного кода, кроме прямого доступа к полю) в любом случае должно быть встроено JIT-компилятором как прямой доступ.
Преимущество использования properties даже в этих простых случаях (в большинстве ситуаций) заключалась в том, что, записывая его как свойство, вы допускаете будущие изменения, которые могут изменить свойство. (Хотя в вашем случае, конечно, в будущем таких изменений не будет)
Here's some scenarios where it is OK (from the Framework Design Guidelines book):
- DO use constant fields for constants это никогда не изменится.
- ОБЯЗАТЕЛЬНО использовать общедоступные статические поля только для чтения для предопределенных экземпляры объектов.
А где это не так:
- НЕ присваивайте экземпляры изменяемых типы для полей только для чтения.
Из того, что вы сказали, я не понимаю, почему ваши тривиальные свойства не вставляются JIT?
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:
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.
Учитывая, что вы имеете дело с неизменяемыми объектами с полями только для чтения, я бы сказал, что вы попали в тот случай, когда я не считаю общедоступные поля грязной привычкой.
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).
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.
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();