Мой вопрос касается характеристик производительности статических методов по сравнению с методами экземпляра и их масштабируемости. Предположим для этого сценария, что все определения классов находятся в одной сборке и что требуется несколько типов дискретных указателей.
Рассматривать:
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
том же экземпляре.
источник
this
указывает на что-то, когда класс вызывает метод экземпляра для себя?»Ответы:
Теоретически статический метод должен работать немного лучше, чем метод экземпляра, при прочих равных условиях, из-за дополнительного скрытого
this
параметра.На практике это так мало разницы, что будет скрыто в шуме различных решений компилятора. (Следовательно, два человека могут «доказать» один лучше другого с несовпадающими результатами). Не в последнюю очередь потому, что
this
обычно передается в регистре и часто изначально находится в этом регистре.Этот последний пункт означает, что теоретически мы должны ожидать, что статический метод, который принимает объект в качестве параметра и что-то с ним делает, будет немного хуже, чем эквивалент в качестве экземпляра для того же объекта. Опять же, разница настолько мала, что, если вы попытаетесь ее измерить, вы, вероятно, в конечном итоге примете какое-то другое решение компилятора. (Тем более, что вероятность того, что эта ссылка все время находится в регистре, тоже довольно высока).
Реальные различия в производительности будут зависеть от того, есть ли у вас в памяти искусственные объекты для выполнения чего-то, что естественно должно быть статическим, или вы запутываете цепочки передачи объектов сложными способами, чтобы делать то, что естественно должно быть экземпляром.
Следовательно, для номера 1. Когда сохранение состояния не является проблемой, всегда лучше быть статичным, потому что для этого статика и предназначена . Это не проблема производительности, хотя есть общее правило хорошей игры с оптимизацией компилятора - более вероятно, что кто-то приложил усилия для оптимизации случаев, которые возникают при нормальном использовании, чем тех, которые возникают со странным использованием.
Номер 2. Без разницы. Существует определенная сумма затрат на класс для каждого члена, она зависит как от количества метаданных, так и от количества кода в фактическом файле DLL или EXE, а также от количества измененного кода. Это одно и то же, будь то экземпляр или статический.
С пунктом 3
this
все какthis
есть. Однако обратите внимание:this
Параметр передается в конкретном регистре. При вызове метода экземпляра в том же классе он, скорее всего, уже будет в этом регистре (если он не был спрятан и регистр не использовался по какой-либо причине), и, следовательно, не требуется никаких действий для установки того,this
что ему нужно установить на . В определенной степени это относится, например, к первым двум параметрам метода, которые являются первыми двумя параметрами вызываемого им вызова.Поскольку будет ясно, что
this
это не NULL, в некоторых случаях это можно использовать для оптимизации вызовов.Поскольку будет ясно, что
this
это не null, это может снова сделать вызовы встроенных методов более эффективными, поскольку код, созданный для имитации вызова метода, может опускать некоторые проверки на null, которые могут потребоваться в любом случае.Тем не менее, нулевые чеки дешевы!
Стоит отметить, что общие статические методы, действующие на объект, а не методы экземпляра, могут снизить некоторые затраты, обсуждаемые на http://joeduffyblog.com/2011/10/23/on-generics-and-some-of- the-associated-overheads / в случае, когда эта статика не вызывается для данного типа. По его словам, «в стороне, оказывается, что методы расширения - отличный способ сделать общие абстракции более выгодными».
Однако обратите внимание, что это относится только к созданию экземпляров других типов, используемых методом, которые иначе не существуют. Таким образом, он действительно не применяется во многих случаях (какой-то другой метод экземпляра использовал этот тип, какой-то другой код где-то еще использовал этот тип).
Резюме:
Изменить: примечание о том, насколько дешевы нулевые проверки (что я утверждал выше). Большинство нулевых проверок в .NET вообще не проверяют наличие null, скорее они продолжают то, что собирались делать, с предположением, что это будет работать, и если возникает исключение доступа, оно превращается в файл
NullReferenceException
. Таким образом, в большинстве случаев, когда концептуально код C # включает проверку на null, поскольку он обращается к члену экземпляра, стоимость в случае успеха фактически равна нулю. Исключением могут быть некоторые встроенные вызовы (потому что они хотят вести себя так, как если бы они вызывали член экземпляра), и они просто попадают в поле, чтобы вызвать такое же поведение, поэтому они также очень дешевы, и их все равно часто можно не учитывать. (например, если первый шаг в методе включал доступ к полю как есть).источник
this
или через явный параметр. Большее влияние здесь будет иметь то, насколько данные близки к связанным данным (поля типа значения или значения массива ближе, чем данные в полях ссылочного типа), и шаблоны доступа.obj.DoSomehting(2)
что это будет немного дешевле,DoSomething(obj, 2)
но, как я также сказал, разница настолько мала и настолько зависит от крошечных вещей, которые могут оказаться разными в финальной компиляции, что на самом деле не стоит беспокоиться вообще. Если вы делаете что-то столь же дорогое (относительно различий в игре), как сериализацию чего-либо в строку, то это особенно бессмысленно.ctor
прежнему требуется инициализация всех полей. Если у вас уже есть экземпляр, применяется этот ответ («при прочих равных»). Конечно, из-за дороговизныcctor
статические методы тоже могут замедлиться, но только при первом вызове они одинаково применяются к методам экземпляра. См. Также docs.microsoft.com/en-us/previous-versions/dotnet/articles/…Я бы сказал, да. Объявляя что-то,
static
вы заявляете о намерении выполнения без сохранения состояния (это не обязательно, но есть намерение чего-то, чего можно было бы ожидать)Не думайте так, если вы не уверены, что статические классы действительно бесхитростны, потому что в противном случае это легко испортить распределение памяти и получить утечки памяти.
Не уверен, насчет этого момента (это чисто деталь реализации CLR), но думаю, что да.
источник
статические методы быстрее, но менее ООП, если вы будете использовать статический метод шаблонов проектирования, вероятно, плохой код, чтобы лучше писать бизнес-логику без статических, общих функций, таких как чтение файлов, WebRequest и т. д., лучше понимать как статические ... у вас нет универсальных вопросов ответ
источник