.NET Integer против Int16?
Вопрос
У меня сомнительная практика кодирования.
Когда мне нужно перебрать небольшой список элементов, предел количества которых меньше 32000
, Я использую Int16
для меня я тип переменной вместо Integer
.Я делаю это, потому что предполагаю использование Int16
более эффективен, чем полноценный Integer
.
Я ошибаюсь?Нет ли эффективной разницы в производительности между использованием Int16
против Integer
?Должен ли я прекратить использование Int16
и просто придерживайся Integer
для всех моих потребностей в подсчете/итерации?
Решение
Согласно приведенной ниже ссылке, время выполнения оптимизирует производительность Int32 и рекомендует их для счетчиков и других часто используемых операций.
Из книги: Комплект для самостоятельного обучения MCTS (экзамен 70-536):Microsoft® .NET Framework 2.0 — Фонд разработки приложений
Глава 1:«Основы фреймворка»
Урок 1:«Использование типов значений»
Лучшие практики:Оптимизация производительности со встроенными типами
Среда выполнения оптимизирует производительность 32-разрядных целочисленных типов (Int32 и UInt32), поэтому используйте эти типы для счетчиков и других часто используемых целочисленных переменных.
Для операций с плавающей запятой тип Double является наиболее эффективным, поскольку эти операции оптимизируются аппаратно.
Кроме того, в Таблице 1-1 в том же разделе перечислены рекомендуемые варианты использования каждого типа.Соответствующее этому обсуждению:
- Int16 — взаимодействие и другие специализированные применения
- Int32 — Целые числа и счетчики
- Int64 — большие целые числа
Другие советы
Вам следует почти всегда использовать Int32
или Int64
(и нет, вы не получите кредит, используя UInt32
или UInt64
) при циклическом переборе массива или коллекции по индексу.
Самая очевидная причина того, что он менее эффективен, заключается в том, что все индексы массивов и коллекций, найденные в BCL, принимают Int32
s, поэтому неявное приведение всегда произойдет в коде, который пытается использовать Int16
s как индекс.
Менее очевидная причина (и причина, по которой массивы занимают 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 и вы
Int16 на самом деле может быть меньше эффективен, поскольку инструкции x86 для доступа к слову занимают больше места, чем инструкции для доступа к dword.Это будет зависеть от того, что сделает JIT.Но несмотря ни на что, это почти наверняка не так. более эффективен при использовании в качестве переменной в итерации.
Верно обратное.
32-битные (или 64-битные) целые числа работают быстрее, чем int16.В общем, собственный тип данных является самым быстрым.
Int16 хорош, если вы хотите сделать свои структуры данных максимально компактными.Это экономит место и может повысить производительность.
Любая разница в производительности на современном оборудовании будет настолько незначительной, что по сути не будет иметь никакого значения.Попробуйте написать пару тестовых программ и запустить их обе несколько сотен раз, возьмите среднее время завершения цикла, и вы поймете, что я имею в виду.
Это может иметь смысл с точки зрения хранения данных, если у вас очень ограниченные ресурсы — встроенные системы с крошечным стеком, проводные протоколы, предназначенные для медленных сетей (например,GPRS и т. д.) и так далее.
Никогда не предполагайте эффективность.
Что является или не является более эффективным, будет варьироваться от компилятора к компилятору и от платформы к платформе.Если вы на самом деле не проверили это, невозможно определить, является ли int16 или int более эффективным.
Я бы просто придерживался целых чисел, если только вы не столкнетесь с доказанной проблемой производительности, которую можно исправить с помощью int16.
Используйте Int32 на 32-битных машинах (или Int64 на 64-битных машинах) для максимальной производительности.Используйте меньший целочисленный тип, если вы Действительно обеспокоен тем, сколько места он занимает (хотя может быть и медленнее).
Остальные здесь верны, используйте только меньше, чем Int32 (для 32-битного кода)/Int64 (для 64-битного кода), если он вам нужен для экстремальных требований к хранению или для другого уровня принудительного применения поля бизнес-объекта (в этом случае у вас все равно должна быть проверка уровня свойств, курс).
И вообще, не беспокойтесь об эффективности, пока не возникнут проблемы с производительностью.И в этом случае профилируйте это.И если угадывание и проверка обоими способами во время профилирования вам не помогают, проверьте IL-код.
Хороший вопрос, однако.Вы узнаете больше о том, как компилятор это делает.Если вы хотите научиться программировать более эффективно, хорошей идеей будет изучение основ IL и того, как компиляторы C#/VB выполняют свою работу.
Я не могу себе представить какого-либо существенного прироста производительности на Int16 по сравнению с Int16.инт.
Вы сохраняете некоторые биты в объявлении переменной.
И определенно не стоит заморачиваться, когда меняются характеристики и все, что вы рассчитываете. может поднимитесь сейчас выше 32767, и вы обнаружите, что когда ваше приложение начинает выдавать исключения...
При использовании типа данных меньшего, чем Int32, нет значительного прироста производительности, более того, я где-то читал, что использование Int32 будет быстрее, чем Int16, из-за распределения памяти.