Производительность статических методов и методов экземпляра

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

Рассмотрим:

public sealed class InstanceClass
{
      public int DoOperation1(string input)
      {
          // Some operation.
      }

      public int DoOperation2(string input)
      {
          // Some operation.
      }

      // … more instance methods.
}

public static class StaticClass
{
      public static int DoOperation1(string input)
      {
          // Some operation.
      }

      public static int DoOperation2(string input)
      {
          // Some operation.
      }

      // … more static methods.
}

Вышеуказанные классы представляют собой шаблон стиля помощника.

В классе экземпляра решение метода экземпляра занимает некоторое время, чтобы противостоять StaticClass.

Мои вопросы:

  • Сохранение состояния не вызывает беспокойства (никаких полей или свойств не требуется), всегда ли лучше использовать статический класс?

  • Если существует значительное количество этих статических определений классов (например, 100, например, с несколькими статическими методами), это будет отрицательно влиять на производительность выполнения или потребление памяти по сравнению с тем же числом определений классов экземпляра

  • Когда вызывается другой метод внутри одного класса экземпляра, сохраняется ли разрешение экземпляра? Например, используя ключевое слово [this], например this.DoOperation2("abc"), из DoOperation1 того же экземпляра.

Ответы

Ответ 1

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

На практике это делает так мало различий, что он будет скрыт в шуме различных решений компилятора. (Следовательно, два человека могли бы "доказать" одно лучше другого с несогласованными результатами). Не в последнюю очередь, поскольку this обычно передается в регистр и часто начинается с этого регистра.

Эта последняя точка означает, что в теории мы должны ожидать, что статический метод принимает объект как параметр и делает что-то с ним немного менее хорошим, чем эквивалент, как экземпляр на том же самом объекте. Опять же, разница настолько незначительна, что, если вы попытались ее измерить, вы, вероятно, в конечном итоге измерили бы какое-то другое решение для компилятора. (Тем более, что вероятность того, что эта ссылка находится в регистре, все время тоже довольно высока).

Реальные различия в производительности снизятся до того, что вы искусственно получили объекты в памяти, чтобы делать что-то, что должно быть естественно статическим, или вы запутываете цепи передачи объектов сложными способами, чтобы делать то, что, естественно, должно быть экземпляром.

Следовательно, для числа 1. Когда сохранение состояния не вызывает беспокойства, всегда лучше быть статичным, , потому что это статическое значение для. Это не проблема производительности, хотя есть общее правило хорошо играть с оптимизацией компилятора - более вероятно, что кто-то пошел на оптимизацию случаев, которые приходят с нормальным использованием, чем те, которые приходят с странным использованием.

Номер 2. Не имеет значения. Там определенная стоимость каждого класса для каждого члена, это условия как количества метаданных там, сколько кода есть в фактическом DLL или EXE файле, и сколько будет jitted-кода. Это то же самое, будь то экземпляр или статический.

С пунктом 3, this выполняется как this. Однако обратите внимание:

  • Параметр this передается в конкретном регистре. При вызове метода экземпляра в пределах одного класса он, скорее всего, будет в этом регистре (если он не был спрятан и регистр не использовался по какой-либо причине), и, следовательно, не требуется никаких действий, чтобы установить this в том, что ему нужно должен быть установлен. Это в определенной степени относится к, например, первые два параметра для метода являются первыми двумя параметрами вызываемого им вызова.

  • Поскольку будет ясно, что this не является нулевым, это может быть использовано для оптимизации вызовов в некоторых случаях.

  • Поскольку будет ясно, что this не является нулевым, это может привести к тому, что вызовы вложенных методов будут более эффективными снова, поскольку код, созданный для подделки вызова метода, может опустить некоторые проверки нулей, которые могут потребоваться в любом случае.

  • Тем не менее, нулевые чеки дешевы!

Стоит отметить, что общие статические методы, действующие на объект, а не методы экземпляров, могут уменьшить некоторые из затрат, обсуждаемых в http://www.bluebytesoftware.com/blog/2011/10/23/OnGenericsAndSomeOfTheAssociatedOverheads.aspx в случае, если данный заданный статический не вызывается для данного типа. По его словам, "в стороне, оказывается, что методы расширения - отличный способ сделать родовые абстракции более платными за игру".

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

Резюме:

  • В основном затраты на производительность экземпляра vs static ниже пренебрежимо малой.
  • Какие расходы, как правило, возникают там, где вы, например, злоупотребляете статикой или наоборот. Если вы не сделаете это частью своего решения между статикой и экземпляром, вы, скорее всего, получите правильный результат.
  • Существуют редкие случаи, когда статические общие методы в другом типе приводят к созданию меньшего количества типов, чем примеры общих методов, которые могут сделать его иногда небольшим преимуществом для использования редко используемых (и "редко" относится к тем типам, которые он использовал в течение всего срока службы приложения, а не о том, как часто он называется). Как только вы узнаете, о чем он говорит в этой статье, вы увидите, что это 100% не имеет отношения к большинству решений статического vs-экземпляра. Изменить: И в основном это имеет только стоимость с ngen, а не с jitted-кодом.

Изменить: примечание о том, как дешевые нулевые чеки (о чем я говорил выше). Большинство нулевых проверок в .NET вообще не проверяют значение null, скорее они продолжают то, что они собираются делать с предположением, что он будет работать, и если произойдет исключение доступа, оно превратится в NullReferenceException. Таким образом, в основном, когда концептуально код С# включает проверку нуля, поскольку он обращается к члену экземпляра, стоимость, если он преуспевает, на самом деле равен нулю. Исключением будут некоторые встроенные вызовы (потому что они хотят вести себя так, как если бы они вызывали члена экземпляра), и они просто попали в поле, чтобы вызвать одно и то же поведение, поэтому они также очень дешевы, и их все равно часто можно оставить в любом случае (например, если первый шаг в способе связан с доступом к полю, как он был).

Ответ 2

При сохранении состояния это не проблема (никакие поля или свойства не являются требуется), всегда лучше использовать статический класс?

Я бы сказал, да. Объявляя что-то static, вы объявляете намерение выполнить безгосударственное исполнение (это не обязательно, а намерение чего-то ожидать)

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

Не думайте так, если вы не уверены в том, что статические классы действительно беспроблемны, потому что, если это не просто избавиться от распределения памяти и получить утечки памяти.

Когда ключевое слово [this] используется для вызова другого метода в пределах одного и того же экземпляр класса, разрешение экземпляра все еще происходит?

Не уверен, об этом пункте (это чисто детализация CLR), но думаю, да.

Ответ 3

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