Модераторы: Partizan, gambit

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> оптимизация цикла 
V
    Опции темы
source777
Дата 25.12.2008, 01:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1878
Регистрация: 12.3.2007

Репутация: 3
Всего: 56



Да, было дело... И, как видишь, вновь нашлись люди, которые на основании синтетических тестов готовы бросаться в крайности...
Но обо всём по порядку, во-первых работа с массивами в .NET встречается довольно редко, в десятки раз чаще практическое применение находят классы-коллекции из System.Collections.Generic. В них foreach реализован гораздо более эффективно.
Во-вторых, перебор коллекции только ради перебора можно встретить лишь в синтетических тестах, я думаю, ты согласишься, что в реальном приложении код типа 
Код

for (int j = 0; j < arr.Count; j++) {}
// или
foreach (Stub j in arr) {}

просто недопустим.
Отсюда мы приходим к важному выводу, что мы обычно перебираем коллекцию, чтобы выполнить с каждым её элементом некоторые действия...
А вот тут-то и выплывает неучтённый горе-авторами всяких синтетических тестов аспект:
доступ к элементу коллекции через итератор гораздо быстрее, чем через индексатор!!!
Т.е. из foreach обращаться к членам элемента выгоднее...
Эксплуатируя сей очевидный факт, легко написать синтетический тест, в котором for "проиграет" сравнение с foreach
Код

    public class Stub
    {
        public double a, b, c, d;
        public Stub()
        {
            a = 2.5;
            b = 5.7;
            c = 9.1;
            d = 8;
        }
    }
//....
        static void Main()
        {
            const int elCount = 10000000;
            List<Stub> arr = new List<Stub>(elCount);
            for (int j = 0; j < elCount; j++) arr.Add(new Stub());
            double value = 0;
            Stopwatch t = Stopwatch.StartNew();
            foreach (Stub el in arr)
            {
                value = el.a + el.b + el.c;
                value *= el.d / el.a - el.c;
            }
            t.Stop();
            Console.WriteLine("foreach: {0} -- {1}", t.ElapsedMilliseconds, value);
            value = 0;
            t = Stopwatch.StartNew();
            for (int j = 0; j < arr.Count; j++)
            {
                value = arr[j].a + arr[j].b + arr[j].c;
                value *= arr[j].d / arr[j].a - arr[j].c;
            }
            t.Stop();
            Console.WriteLine("for: {0}  -- {1}", t.ElapsedMilliseconds, value);
            Console.ReadLine();
      }

В Release-версии этот код выдаёт примерно такие результаты:
Цитата

foreach: 353
for: 739

Т.о. цикл с for оказался в 2 раза медленнее цикла с foreach.

Как видишь, стоило проигнорировать простой факт того, что доступ к элементу коллекции через итератор гораздо быстрее, чем через индексатор и производительность for растаяла в одно мгновенье. Ну и кому нужна такая оптимизация?
Естественно, легко догадаться как оптимизировать вариант с for, необходимо запомнить значение(точнее ссылку на него) текущего элемента во временной переменной, а не дёргать каждый раз индексатор.
Код

value = 0;
            t = Stopwatch.StartNew();
            for (int j = 0; j < arr.Count; j++)
            {
                Stub el = arr[j];
                value = el.a + el.b + el.c;
                value *= el.d / el.a - el.c;
            }
            t.Stop();
            Console.WriteLine("for optimize: {0}  -- {1}", t.ElapsedMilliseconds, value); 

Этот вариант выводит 354, т.е. время того же порядка, что и foreach, только писать больше букв пришлось...


P.S. Вывод: не доверяйте синтетическим тестам, и уж ни в коем случае не принимайте никаких "оптимизационных" решений на их основе пока не разберётесь сами с данным вопросом и не убедитесь при помощи профайлера, что вы взялись за оптимизацию действительно узкого места производительности. 

Это сообщение отредактировал(а) source777 - 25.12.2008, 01:16


--------------------
Если бы программистам платили за то, чтобы убирать код из программы вместо того, чтобы добавлять его, программы были бы намного лучше © Николас Негропонте
PM MAIL   Вверх
Luter
Дата 25.12.2008, 02:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 34
Регистрация: 17.12.2008

Репутация: нет
Всего: 1



source777 Просто твой код не оптимизирован, потому и медленый for, а в foreach  не нада оптимизировать, потому быстрый, но в foreach уде время на преобразование и на оптимизацию.

Компилятор преобразовует foreach  в for  и оптимизирует, а неа преобразование йдут доли секунды.
Если вы умеете оптимизировать, то лучше пользуйтесь for, если нет то лучше foreach.
PM MAIL   Вверх
source777
Дата 25.12.2008, 13:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1878
Регистрация: 12.3.2007

Репутация: 3
Всего: 56



Цитата(Luter @  25.12.2008,  02:24 Найти цитируемый пост)
source777 Просто твой код не оптимизирован, потому и медленый for, а в foreach  не нада оптимизировать, потому быстрый, но в foreach уде время на преобразование и на оптимизацию.
Компилятор преобразовует foreach  в for  и оптимизирует
Это ошибочная точка зрения, домашнее задание тебе: посмотри MSIL-код и убедись в том, что код, сгенерированный foreach, принципиально отличается от кода, сгенерированного for.



--------------------
Если бы программистам платили за то, чтобы убирать код из программы вместо того, чтобы добавлять его, программы были бы намного лучше © Николас Негропонте
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
Partizan
PashaPash

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.
Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :)
Так же не забывайте отмечать свой вопрос решенным, если он таковым является :)


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, Partizan, PashaPash.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | .NET для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.5283 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.