Вопрос чисто ради интереса. Code: for (int i = 0; i < someshit.count(); i++) {} Code: int arraySize = someshit.count(); for (int i = 0; i < arraySize; i++) {} В первом случае метод count() вызывается Х количество раз. Во втором - один раз. Интересует мнение людей, которые знают как это работает на более низком уровне. Много ли различных вызовов\обращений к памяти экономит второй пример и есть ли вообще смысл оптимизировать код данным образом?
в вопросе и ответ, если не хочешь count() вызывать тыщу раз то стоит, проголосовал за второй вариант, хотя пишу в Делфи а там разницы нет
второй вариант значительно будет виден когда someshit.count() будет около 1кк или больше... смотря конечно что такое someshit если это класс а count() функция, то надо смотреть как она получает результат... тут может быть несколько споссобов 1)ф-ия в цикле считает результат и выдает... 2)в классе предусмотрена переменная для хранения этого результата, которая при каждом изменеии данных пересчитывается и сохраняется в памяти тогда count() просто считывает эту переменную и выдает её результат. сам понимаеш если первый вариант то это очень много лишних операций для тебя... если же в классе все как во втором случае то ты всеравно на каждый шаг цикла получаеш 1-2 лишних операции... p.s. если ты уверен что значение count() у тебя всегда будет не больше 1000 то оба споссоба для человека будут одинаковы (человек не сможет заметить разницу выполнения программ в 100-200 тактов (ну может и побольше))
второй вариант, только пишу так: Code: for (int i = 0, arraySize = someshit.count(); i < arraySize; i++) {}
Конечно второй вариант быстрее. З.Ы. А если ещё и цикл разложить в последовательные вызовы и таким образом избавиться от условия на каждой итерации, так вообще Но это не твой случай, т.к. ты не знаешь count. Единственное - умные компиляторы всё это дело оптимизируют. З.З.Ы. А по поводу названия опроса "Как вы пишете", я пишу как во 2м варианте, но к примеру Фаулер, в книге по рефакторингу рекомендует писать как в первом варианте, для того чтобы избавится от лишних переменных и сделать код более наглядным. Ну это правда к этапу оптимизации не относится, а делается раньше
думаю не стоит к этому прислушиваться.... ибо код надо форматировать только потому что мы не машины и если писать код в одну строчку то его сразу не понять...(очень не сразу..) но самое главное для программиста должно быть оптимизация и отсутствие багов в своем детище (не если не отсутствию, то хотябы свести все баги к минимуму...) а наглядность это не для кода... (но если кодер ставит на первый план наглядность то это его дело)
KIR@PRO, код пишут для людей а не для компов. (Ну без фанатизма, я к тому что код должен быть понятен) В больших проектах за непонятный код надо по пальцам стучать. Представь как его потом апдейтить и багфиксить. Но по мне временные переменные - наоборот могут внести ясность, за счёт нормального имени переменной. З.Ы. А оптимизация это уже последний этап, когда код работает и ты по нему бегаешь профайлером, выясняя что именно стоит оптимизировать.
дак я и говорю что элементарную табуляцию и прочее надо соблюдать, названия переменных делать понятными... это уде слишком, этож прямое принебрежение производительностью ради маленькой наглядности... p.s. может мы просто не поняли друг друга))) я же говорил именно о том что надо избавляться от временных переменных чтоб сделать код более наглядным... p.p.s. но это мнение каждого из нас)
по-моему такого вообще не должно быть, должна быть переменная Size, которая обновляется сама собой. проголосовал за первое, случайно.
посмотрел... результат под запуском профайлера: результат профайлера: используемый код: PHP: using System; using System.Collections.Generic; namespace ConsoleApplication1 { class Program { private const int MaxLength = 100000; private static readonly List<int> list = new List<int>(); static void GetList() { int i = 0; while (i < MaxLength) { list.Add(i); i++; } } static DateTime Method1() { for (int i = 0; i < list.Count; i++) { int a; a = i ^ 100; int b = a >> 2 << 3; } return DateTime.Now; } static DateTime Method2() { int size = list.Count; for (int i = 0; i < size; i++) { int a; a = i ^ 100; int b = a >> 2 << 3; } return DateTime.Now; } static void Main() { GetList(); var a = DateTime.Now; Console.WriteLine(string.Format("Method 1. Time elapsed: {0}", (Method1() - a))); a = DateTime.Now; Console.WriteLine(string.Format("Method 2. Time elapsed: {0}", (Method2() - a))); Console.ReadLine(); } } } надеюсь я не тупанул, хотя как оговаривалось ранее, все зависит от реализации используемого объекта. p.s. было интересно, а будет-ли разница? Оказалось есть. Проц Core2Duo E8400
В примере топикстартера используется метод someshit.count(); , а не свойство, как у тебя. В твоем примере разница между вызовом свойства и локальной переменной - минимальна. А вот если count() - это метод, со сложной внутренней реализацией, то разница будет намного большей. PS Да, и использованный тест не очень показателен. Нужно что бы время выполнения было хотя бы несколько секунд. Разница в 3 сотых - вполне может быть случайной. Особенно в дотнете.
В том то и дело, что как правило внутри класса есть такая переменная, но почему-то во многих фреймворках, например в QT делается так, что все свойства закрытые, а доступ к ним получаем через методы. Довольно часто можно встретить такое: Code: class a { public: int count() { return size;} private: int size; };
На данный момент, доступ к переменным через геттеры/сеттеры - стандарт. (И это действительно оправдано) З.Ы. Если не понятно почему, то во первых чтобы со стороны никто не мог внезапно изменить данное поле (в случае public ты можешь записать левое значение в переменную size и класс об этом не узнает, чем черевато - понятно), а так ты можешь сделать поле доступным извне только на чтение, или только на запись, во вторых если требуется изменить внутреннюю структуру класса и удалить/переименовать эту переменную, чтобы не требовалось искать всех пользователей класса, и менять их. (Просто достаточно будет изменить реализацию геттеров/сеттеров, тогда интерфейс класса останется неизменным). Вот по крайней мере 2 плюса использования геттеров сеттеров. Ну ещё можно при помощи изменения геттеров подгонять объекты под требования пользователя класса, или добавлять в них проверки ввода, но сложная логика в геттерах/сеттерах - не клёво и неправильно.
Проголосовал за 1-й вариант, потом вдумался и пришёл к выводу что пишу всё-же по второму варианту. В принципе если метод count() имеет какую то сложную реализацию то это существенно скажется на производительность.
хм так и знал что глупость сделал, но думаю это можно решить если использовать LINQ запрос. вечером как окажусь дома переделаю... думаю будет нагляднее. update: не выдержал, проверил с LINQ на работе, результат без профайлера: Method 1. Time elapsed: 00:00:00.0468753 Method 2. Time elapsed: 00:00:00 update2: с профайлером: Method 1. Time elapsed: 00:00:00.0781250 Method 2. Time elapsed: 00:00:00.0156250
сколько раз гонялся тест? нужно минимум для каждого варианта прогнать по 10-50 раз. чтобы исключить момент подгрузки кода в кеш. по поводу опроса - не хватает еще варианта ответа - одно***ственно. ибо потери на вызове метода, пусть даже виртуального, не окажут никакого ощутимого влияния. а лишняя локальная переменная в таком месте, объявленная вне цикла, может позже помешать вынести этот цикл в отдельный метод. так что чисто из соображений дальнейшей поддержки проекта и читабельности я бы предпочел первый вариант. по поводу форматирования - почитайте Макконнелла. по поводу переменных - int x = strlen("blabla") - strlen("bla"); на уровне асма будет эквивалентен коду int blabla_len = strlen("blabla"); int bla_len = strlen("bla"); int blabla_len_dif = blabla_len - bla_len; суть отказа от локальных переменных как раз в другом. чтобы в больших методах можно было легко читать логику. этот код например в случае нахождения в большом методе выносится в отдельный и заменяется на blabla_len_dif("blabla", "bla"); ибо это понятнее и требует меньше времени на чтения, ибо банально занимает 1 строку. ну и в добавок сей код можно в дальнейшем вызывать из любого места класса, плюс сделать метод публичным и дать другим классам с ним работать. зы: чтите Фаулера, Макконнелла, GoF.
Совет: пишите так, как проще и меньше кода. Оптимиировать надо не все подряд, а только узкие места. Все подряд оптимизируют лишь распиздяи