.NET Integer против Int16? - PullRequest
       9

.NET Integer против Int16?

50 голосов
/ 24 сентября 2008

У меня сомнительная практика кодирования.

Когда мне нужно пройтись по небольшому списку элементов, предел количества которых меньше 32000, я использую Int16 для моего i типа переменной вместо Integer. Я делаю это, потому что я полагаю, что использование Int16 более эффективно, чем полноценное Integer.

Я не прав? Нет ли разницы в эффективной производительности между использованием Int16 против Integer? Должен ли я прекратить использовать Int16 и просто придерживаться Integer для всех моих потребностей подсчета / итерации?

Ответы [ 10 ]

84 голосов
/ 25 сентября 2008

Вы должны почти всегда использовать Int32 или Int64 (и, нет, вы не получаете кредит при использовании UInt32 или UInt64) при циклическом просмотре массива или коллекции по индексу .

Наиболее очевидная причина, по которой он менее эффективен, состоит в том, что все индексы массивов и коллекций, найденные в BCL, принимают Int32 с, поэтому неявное приведение всегда происходит в коде, который пытается использовать Int16 с в качестве индекса.

Менее очевидная причина (и причина, по которой массивы принимают Int32 в качестве индекса) состоит в том, что спецификация CIL говорит, что все значения стека операций либо Int32 или Int64. Каждый раз, когда вы загружаете или сохраняете значение для любого другого целочисленного типа (Byte, SByte, UInt16, Int16, UInt32 или UInt64), возникает неявная операция преобразования. Для неподписанных типов штраф за загрузку отсутствует, но для хранения значения это означает усечение и возможную проверку переполнения. Для типов со знаком каждая знак загрузки расширяется, а каждый магазин складывается (и имеет возможную проверку переполнения).

Место, из-за которого вам будет больно больше всего, - это сам цикл, а не доступ к массиву. Например, возьмем этот невинно выглядящий цикл:

for (short i = 0; i < 32000; i++) {
    ...
}

Хорошо выглядит, верно? Нету! Вы можете игнорировать инициализацию (short i = 0), поскольку она происходит только один раз, но части сравнения (i<32000) и увеличения (i++) происходят 32000 раз. Вот некоторый псевдо-код того, как эта штука выглядит на уровне машины:

  Int16 i = 0;
LOOP:
  Int32 temp0 = Convert_I16_To_I32(i); // !!!
  if (temp0 >= 32000) goto END;
  ...
  Int32 temp1 = Convert_I16_To_I32(i); // !!!
  Int32 temp2 = temp1 + 1;
  i = Convert_I32_To_I16(temp2); // !!!
  goto LOOP;
END:

Есть 3 преобразований, которые выполняются 32000 раз. И их можно было полностью избежать, просто используя Int32 или Int64.

Обновление: Как я уже сказал в комментарии, я фактически написал сообщение в блоге на эту тему: .NET Integral Data Types And You

52 голосов
/ 25 сентября 2008

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

Из книги: Учебный комплект MCTS для самостоятельного обучения (экзамен 70-536): Microsoft® .NET Framework 2.0 - Фонд разработки приложений

Глава 1: «Основы основ»
Урок 1: «Использование типов значений»

Рекомендации: оптимизация производительности со встроенными типами

Среда выполнения оптимизирует производительность 32-разрядных целочисленных типов (Int32 и UInt32), поэтому используйте эти типы для счетчиков и других часто используемых интегральных переменных.

Для операций с плавающей запятой Double является наиболее эффективным типом, поскольку эти операции оптимизируются аппаратно.

Кроме того, в таблице 1-1 в том же разделе перечислены рекомендуемые применения для каждого типа. Относящиеся к этой дискуссии:

  • Int16 - Взаимодействие и другое специальное использование
  • Int32 - Целые числа и счетчики
  • Int64 - Большие целые числа
11 голосов
/ 24 сентября 2008

Int16 может фактически быть менее эффективным, потому что инструкции x86 для доступа к словам занимают больше места, чем инструкции для доступа к слову. Это будет зависеть от того, что делает JIT. Но несмотря ни на что, это почти наверняка не более эффективно, когда используется в качестве переменной в итерации.

9 голосов
/ 24 сентября 2008

Верно обратное.

32 (или 64) битовых числа быстрее, чем int16. В общем родной тип данных самый быстрый.

Int16 хороши, если вы хотите сделать ваши структуры данных максимально простыми. Это экономит место и может улучшить производительность.

3 голосов
/ 24 сентября 2008

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

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

2 голосов
/ 24 сентября 2008

Используйте Int32 на 32-битных машинах (или Int64 на 64-битных машинах) для максимальной производительности. Используйте меньший целочисленный тип, если вы действительно беспокоитесь о занимаемом месте (хотя и медленнее).

2 голосов
/ 24 сентября 2008

Никогда не принимайте эффективность.

То, что является или не является более эффективным, будет варьироваться от компилятора к компилятору и от платформы к платформе. Если вы на самом деле не проверили это, невозможно определить, эффективнее ли int16 или int.

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

1 голос
/ 26 сентября 2008

Остальные значения верны, используйте только меньше Int32 (для 32-разрядного кода) / Int64 (для 64-разрядного кода), если оно требуется для экстремальных требований к хранилищу или для другого уровня принудительное применение в поле бизнес-объекта (в этом случае, конечно, вы все равно должны пройти валидацию надлежащего уровня)

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

Хороший вопрос, хотя. Вы узнаете больше о том, как компилятор делает это. Если вы хотите научиться более эффективно программировать, было бы полезно изучить основы IL и то, как компиляторы C # / VB выполняют свою работу.

0 голосов
/ 24 сентября 2008

Нет существенного увеличения производительности при использовании типа данных, меньшего, чем Int32, на самом деле я где-то читал, что использование Int32 будет быстрее, чем Int16 из-за выделения памяти

0 голосов
/ 24 сентября 2008

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

Вы сохраняете несколько битов в объявлении переменной.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...