Было бы уместно также упомянуть, что располагают, не всегда относится к памяти? Я располагаю ресурсы такие ссылки на файлы чаще, чем память. GC.Collect () непосредственно касается сборщика "мусора" CLR, и можете, или не может свободная память (в Диспетчере задач). Это, вероятно, повлияет на Ваше приложение отрицательными способами (например, производительность).
В конце дня, почему Вы хотите память назад сразу? Если будет давление памяти откуда-либо, то ОС получит Вас память в большинстве случаев.
Всем нравятся их микрооптимизации, но, насколько я понимаю, это не имеет значения. Я скомпилировал два варианта с g ++ on для процессоров Intel без каких-либо изысканных оптимизаций, и результаты приведены для
для (int i = 0; i <5; i ++)
movl $0, -12(%ebp)
jmp L2
L3:
leal -12(%ebp), %eax
incl (%eax)
L2:
cmpl $4, -12(%ebp)
jle L3
для (int i = 0; i! = 5; ++ i)
movl $0, -12(%ebp)
jmp L7
L8:
leal -12(%ebp), %eax
incl (%eax)
L7:
cmpl $5, -12(%ebp)
jne L8
Я думаю, что jle
и jne
должны переводиться в одинаково быстрые инструкции на большинстве архитектур.
Так что для производительности вы не должны различать эти два параметра. В общем, я согласен с тем, что первый немного безопаснее и, я думаю, более распространен.
РЕДАКТИРОВАТЬ (2 года спустя): Поскольку эта тема недавно снова привлекла много внимания, я хотел бы добавить что на этот вопрос будет сложно ответить вообще. Какие версии кода более эффективны, в стандарте C [PDF] конкретно не определяется (и то же самое относится к C ++ и, вероятно, также к C #).
Раздел 5.1.2.3 Выполнение программы
§1 Семантические описания в этом международном стандарте описывают поведение абстрактной машины, в которой вопросы оптимизации не имеют значения.
Но разумно предположить, что современный компилятор будет генерировать столь же эффективный код, и я думаю, что только в очень редких случаях тест цикла и подсчетное выражение будут узкое место цикла for.
Что касается вкуса, я пишу
for(int i = 0; i < 5; ++i)
Если бы ваш индекс не был int
, а вместо этого (скажем) классом C ++, то второй пример мог бы быть более эффективен.
Однако, как написано, ваша вера в то, что вторая форма более эффективна, просто неверна. Любой достойный компилятор будет иметь отличные идиомы кодогенератора для простого цикла for и будет генерировать высококачественный код для любого примера. Ближе к делу:
В цикле for, который выполняет тяжелые вычисления, критичные к производительности, арифметические операции с индексами будут составлять почти незначительную часть общей нагрузки.
Если ваш цикл for критичен к производительности и не выполняет тяжелые вычисления так что арифметика индексов действительно имеет значение, вам почти наверняка следует реструктурировать свой код, чтобы выполнять больше работы на каждом проходе цикла.
Ну ... это нормально, пока вы не изменяете i
внутри цикла for. Настоящий «САМЫЙ ЛУЧШИЙ» синтаксис для этого полностью зависит от желаемого результата.
По поводу читаемости. Как программист на C #, которому нравится Ruby, я недавно написал метод расширения для int, который допускает следующий синтаксис (как в Ruby):
4.Times(x => MyAction(x));
Я думаю, что второй вариант менее читабелен (хотя бы потому, что "стандартной" практикой кажется первое).
Если правило приращения немного изменится, вы сразу получите бесконечный цикл. Я предпочитаю первое конечное условие.
In generic code you should prefer the version with !=
operator since it only requires your i
to be equally-comparable, while the <
version requires it to be relationally-comparable. The latter is a stronger requirement than the former. You should generally prefer to avoid stronger requrements when a weaker requirement is perfectly sufficient.
Having said that, in your specific case if int i
both will work equally well and there won't be any difference in performance.
Форма
for (int i = 0; i < 5; i++)
- idiomatic , поэтому его легче читать опытным программистам на C. Особенно, когда используется для перебора массива. По возможности вы должны писать идиоматический код, так как он читается быстрее.
Это также немного безопаснее в ситуациях, когда вы изменяете i внутри цикла или используете приращение, отличное от 1. Но это мелочь. Лучше всего тщательно спроектировать цикл и добавить несколько утверждений, чтобы на раннем этапе отловить неверные предположения.
Что касается использования ++ i вместо i ++, это не имеет значения для большинства компиляторов, однако ++ i может быть более эффективным, чем i ++ при использовании в качестве итератора.
В ваш код добавлены числовые литералы? К стыду ...
Возвращаясь к делу, Дональд Кнут однажды сказал
Мы должны забыть о малых эффективности, говорят около 97% время: преждевременная оптимизация - это корень всего зла.
Итак, все сводится к тому, что легче анализировать
Итак ... принимая во внимание оба вышеперечисленного, что из следующего легче разобрать программисту?
for (int i = 0; i < myArray.Length; ++i)
for (int i = 0; i != myArray.Length; ++i)
Изменить: мне известно, что массивы в C # реализуют интерфейс System.Collections.IList, но это не обязательно верно для других языков.
Я бы никогда этого не сделал:
for(int i = 0; i != 5; ++i)
i! = 5 оставляет возможность, что мне никогда не будет 5. Слишком легко пропустить это и попасть в бесконечный цикл или ошибка доступа к массиву.
++i
Хотя многие люди знают, что ++ можно ставить впереди, многие люди этого не делают. Код должен быть удобочитаемым для людей, и хотя это может быть микрооптимизация, чтобы код работал быстрее, на самом деле это не стоит лишней головной боли, когда кому-то нужно изменить код и понять, почему это было сделано.
Я думаю, что у Дугласа Крокфорда есть лучшее предложение - не использовать ++ или - вообще. Иногда это может просто сбивать с толку (может быть, не в цикле, а в других местах), и так же легко написать i = i + 1. Он думает, что это просто дурная привычка, чтобы избавиться от нее, и я вроде как согласен, увидев ужасный "оптимизированный" код.
Я думаю, что Крокфорд имеет в виду, что с этими операторами вы можете заставить людей писать такие вещи, как:
var x = 0;
var y = x++;
y = ++x * (Math.pow(++y, 2) * 3) * ++x;
alert(x * y);
// ответ 54 кстати.
Если по какой-то причине i
перескочит на 50 в цикле, ваша версия будет повторяться бесконечно. i <5
- это проверка работоспособности.
Это зависит от языка.
Тексты на C ++ часто предлагают второй формат, поскольку он будет работать с итераторами, которые можно сравнивать (! =) Напрямую, но не с условием больше или меньше. Также предварительное приращение может быть быстрее, чем последующее приращение, поскольку нет необходимости в копии переменной для сравнения - однако оптимизаторы могут с этим справиться.
Для целых чисел работает любая форма. Обычная идиома для C - первая, а для C ++ - вторая.
Для C # и Java я бы использовал foreach, чтобы перебирать все вещи.
В C ++ также есть функция std :: for_each, требующая использование функтора, который для простых случаев, вероятно, более сложен, чем любой из приведенных здесь примеров, и Boost FOR_EACH, который может выглядеть как foreach C #, но сложен внутри.