Является ли передача значения структуры путем ссылки на метод в C # приемлемой оптимизацией? - PullRequest
3 голосов
/ 25 мая 2010

Скажите, что у меня есть структура:

struct MyStruct
{
    public int X
    public int Y
}

И метод в каком-то классе, который повторяется много раз в других местах:

public bool MyMethod( MyStruct myStruct )
{
    return ...
}

Является ли изменение подписи MyMethod следующей приемлемой оптимизацией?

public bool MyMethod( ref MyStruct myStruct )

Если так, то какое это было бы преимущество? Если нет, то сколько полей понадобится структуре для достаточно большого преимущества при использовании ref таким образом?

Ответы [ 5 ]

7 голосов
/ 25 мая 2010

В 32-разрядной системе вы вносите изменение, чтобы передать 8 байтов данных вместо 4 в 4. Никаких изменений в объеме данных, передаваемых в 64-битной системе. Вы также добавляете требование к компилятору / JITter, что структура должна существовать в памяти, так как вы собираетесь брать ее адрес, что может свести на нет другие оптимизации.

Я сомневаюсь, что это покажет увеличение производительности вашей программы. Сначала пройдите профиль и посмотрите, не является ли MyMethod узким местом в вашей программе.

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

4 голосов
/ 25 мая 2010

Поскольку вы явно спросили, было ли это «приемлемо»…

Я бы ответил нет . Передав аргумент ref, вы лжете компилятору и программисту; ref в .NET (исключительно) означает, что вы намереваетесь изменить аргумент внутри метода.

Конечно, вы можете предоставить дополнительный комментарий, объясняющий «ложь» программисту (но не компилятору…). Но зачем вообще злоупотреблять семантикой?

Если вам действительно нужны такие экстремальные микрооптимизации (и посмотрите другие ответы - любое преимущество в производительности сомнительно по ряду причин!) .NET может быть просто неправильной средой. Реализуйте соответствующую часть в C ++.

2 голосов
/ 25 мая 2010

Маловероятно, учитывая ваш пример. На 64-битном процессоре структура будет удобно вписываться в регистры, она не будет проходить через стек. Хотя не на 32-битном процессоре, а на методе экземпляра. Когда вы переходите по ссылке, вы платите за доступ к элементам структуры, требуется дополнительная разыменование указателя. Это может стать дороже, чем избежать копирования, мммм.

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

0 голосов
/ 25 мая 2010

В общее Я бы сказал нет: придерживайтесь класса со свойствами. Тем не менее, существуют обстоятельства, которые могут требовать чего-то подобного - в частности, на компактных (например, XNA) или микро-структурных. В обоих случаях GC * очень отличается, и распределение объектов (и недетерминированный сбор) может оказать существенное влияние на приложение.

В таких случаях нередко можно увидеть, как в игру вступает больше структур, и ref позволяет избежать распространенных проблем с «потерянным обновлением» (в большинстве .NET структуры должны быть неизменяемыми; снова XNA имеет некоторые сценарии, из-за которых возникает соблазн нарушить это правило). Другой подход, конечно, заключается в том, чтобы принять и вернуть данные - тогда тип может быть неизменным.

Если вы имеете в виду выполнение передачи объекта; тогда у вас есть для профилирования на точную настройку, которую вы собираетесь использовать. x86 против x64 - очевидная разница, но есть и другие. Например, использование ref требует, чтобы значение находилось либо в поле, либо в локальной переменной, - но многие из настроек производительности JIT для структур работают на верхушке стека - это означает, что у вас может быть намного больше «ldloc» / » stloc "чем тебе строго нужно. Вы также вводите дополнительную разыменование.

0 голосов
/ 25 мая 2010

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

Как только вы начинаете добавлять более двух полей Int, это преимущество начинает расти. Тем не менее, не имеет значения, если вы не вызываете этот метод много .

...