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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Performance рекурсивной функции 
:(
    Опции темы
SCAR
Дата 23.6.2013, 22:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Доброго времени суток!

Добавил в программу следующую рекурсивную функцию:

Код

        private static void signFiller(SignModel mdl, int pathIndex)
        {
            int pathCount = SegX.Instance.getPathListCount() - 1;
            if (pathIndex > pathCount) return;

            ArrayList pthModels = SegX.Instance.getAllModelsForPath(pathIndex);

            SignModel initialMdl = (SignModel)mdl.Clone();

            for (int i = 0; i < pthModels.Count; i++) //Все подпути для данного пути
            {
                //Добавить модель пути в модель знака
                initialMdl.addPathModel((PathModel)pthModels[i]);

                if (pathIndex < pathCount)
                {
                    signFiller(initialMdl, pathIndex + 1); 
                }
                //Следующая модель

                SegX.Instance.addSignModel(initialMdl);
                initialMdl = (SignModel)mdl.Clone();
                modelsCount++;

                Logger.Instance.addLogRecord("SignModels count: " + modelsCount);
            }
        }


Но данная функция работает очень медленно (около 100 итераций в секунду), а с увеличением количества итераций скорость работы замедляется еще раз в 10... Функция Clone() описана ниже: 

Код

        public object Clone()
        {
            SignModel newSignModel = (SignModel)this.MemberwiseClone();
            newSignModel.addPathModelList(new Dictionary<int, PathModel>(this.getPathModelsDict()));
            newSignModel.addAnglesList(new Dictionary<int, Angle>(this.getAnglesDict()));
            return newSignModel;
        }



Подскажите пожалуйста, как ускорить данную процедуру? Я в C# не настолько спец smile

PM MAIL   Вверх
uwannadie
Дата 25.6.2013, 02:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 175
Регистрация: 5.6.2009
Где: Крым, Керчь

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



Для начала попробуй определить, какая часть рекурсивной функции выполняется дольше всего.
Плюс выключи логирование и проверь разницу во времени.
--------------------
PM MAIL   Вверх
IBS
Дата 25.6.2013, 21:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



я бы рекомендовал почитать про развертку рекурсии с помощью стека.
Кстати, таким образом реализовать отложенный возврат элементов (нравится он мне smile)

Это сообщение отредактировал(а) IBS - 25.6.2013, 21:48
PM MAIL   Вверх
SCAR
Дата 26.6.2013, 00:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Большое спасибо! Очень интересная идея про стек. А не подскажите, где почитать можно? В С++ с такими проблемами не сталкивался, а тут... 
PM MAIL   Вверх
IBS
Дата 26.6.2013, 17:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Тут ребята развели прикольный холивар на эту тему:
http://otvety.google.ru/otvety/thread?tid=4ef8214f3d124669

А вообще смысл в том, что нужно выделить основные параметры, которые тебе необходимы на каждой "стековой итерации" и писать их в стек, если писать на данной итерации ничего не надо, то начинаем вытягивать и обрабатывать.
PM MAIL   Вверх
SCAR
Дата 27.6.2013, 15:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Интересная информация, спасибо! Жаль, что большого прироста производительности данный подход не дает, но все же полезен для оптимизации.
PM MAIL   Вверх
SCAR
Дата 14.7.2013, 20:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Как оказалось, слабое место - функция Copy(), особенно это место:

Код

SignModel newSignModel = (SignModel)this.MemberwiseClone();


Подскажите пожалуйста, есть ли какие-то более шустрые альтернативы для MemberwiseClone()? Или, может быть, стоит попробовать создать конструктор копирования для класса?
PM MAIL   Вверх
SCAR
Дата 14.7.2013, 21:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Нашел интересную информацию по данной теме:

http://stackoverflow.com/questions/966451/...copy-in-c-sharp
http://whizzodev.blogspot.com/2008/03/obje...ng-il-in-c.html
Реализовал IL клонирование, как указано в примере. Но только вот, клона эта штука не создает, а создает объект который ссылается на ту же ячейку памяти, ну со всеми выходящими. Меняешь один объект, меняется и второй... Возможно имеет смысл сделать ILCloner рекурсивным, для глубокого копирования?

Это сообщение отредактировал(а) SCAR - 14.7.2013, 23:08
PM MAIL   Вверх
SCAR
Дата 23.7.2013, 09:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Всем привет, 

Я опять с тем же вопросом. Ускорил данную функцию, как только мог, вот наиболее быстрый вариант: 

Код

        private static void signFiller(SignModel mdl, int pathIndex)
        {

            int pathCount = SegX.Instance.getPathListCount() - 1;
            if (pathIndex > pathCount) return;

            ArrayList pthModels = SegX.Instance.getAllModelsForPath(pathIndex);
            
            int pthCnt = pthModels.Count;

            for (int i = 0; i < pthCnt; i++) //Для каждой из моделей строим модель знака, сопоставляя ее с моделями других путей
            {
                //Добавить модель пути в модель знака
                initialMdl.addPathModel((PathModel)pthModels[i]);

                if (pathIndex < pathCount)
                {
                    signFiller(initialMdl, pathIndex + 1); 
                }
                //Следующая модель

                SegX.Instance.addSignModel(initialMdl);

                initialMdl = (SignModel)mdl.Clone();

                modelsCount++;
            }
        }


        public object Clone()
        {

            // High speed
            SignModel result = new SignModel();
            result._pathModels = new Dictionary<int, PathModel>(this._pathModels); //ILCloner.Clone<Dictionary<int, PathModel>>(this._pathModels); //
            result._angles = new Dictionary<int, Angle>(this._angles); //ILCloner.Clone<Dictionary<int, Angle>>(this._angles);

            return result;
        }



В качестве функции клонирования перепробовал все варианты, которые нашел в интернете, к примеру: Deep IL Cloning, Reflection cloning, MemberwiseClone, BinnaryFormatter (с использованием MemoryStream и Serialize). Кстати, последний способ - наиболее медленный.
Но проблема так и не исчезла, первые 25000 моделей формируются очень быстро (меньше секунды), но дальше - хуже. С каждой новой итерацией скорость работы существенно замедляется и когда кол-во моделей достигает отметки в пол миллиона, то скорость формирования моделей становится около 50 шт./сек. 
Размер объектов SignModel всегда примерно один и тот же, т.е. это  не может происходить из-за увеличения размера клонируемых данных. 
Подскажите пожалуйста, на что стоит обратить внимание? 
PM MAIL   Вверх
mihryak
Дата 23.7.2013, 14:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 19
Всего: 36



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

скачай любой профайлер - хоть ant, хоть jetbrains, хоть любой другой, они все имеют беплатный период. не разберёшься в отчётах - выкладывай сюда.

пс. я подозреваю, что дело вовсе не в клонировании, а вообще в подходе к решению задачи, но, опять-таки, без профилирования никаких выводов делать нельзя.
PM MAIL ICQ   Вверх
SCAR
Дата 23.7.2013, 20:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Большое спасибо за совет!

Профайлер указал на процедуру SegX.Instance.addSignModel(initialMdl);

Она выглядит следующим образом:

Код

        public void addSignModel(SignModel model)  //Добавляет модель знака в список
        {
            if(signModels.IndexOf(model) < 0)
                signModels.Add(model);
        } 


Затык на ArrayList.IndexOf, подскажите пожалуйста, какие есть альтернативы? Чем можно заменить использование IndexOf? 
Я читал про BinarySearch, но он требует сортировки списка, а я не думаю, что сортировка будет быстрее.

Лог профайлера:

http://s1.ipicture.ru/uploads/20130723/CchKD6Ap.bmp

Это сообщение отредактировал(а) SCAR - 23.7.2013, 21:02
PM MAIL   Вверх
SCAR
Дата 23.7.2013, 21:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Заменил ArrayList на Dictionary<long, SignModel>, стало работать очень быстро, но случилась другая проблема  smile 
Когда создается 5999472 модели, то Dictionary выплевывает System.OutOfMemoryException )) 
Как можно добавить ему памяти, чтоб можно было разместить больше объектов?

Это сообщение отредактировал(а) SCAR - 23.7.2013, 21:30
PM MAIL   Вверх
mihryak
Дата 23.7.2013, 21:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 19
Всего: 36



5999472 объектов в памяти - безумно много
надо смотреть в сторону базы данных, мне кажется, это неизбежно
PM MAIL ICQ   Вверх
SCAR
Дата 23.7.2013, 22:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Согласен, что много, но надо больше. А даст ли база такой перформанс? И не могли бы вы посоветовать, в сторону чего смотреть? 
Была глупая идея, сделать несколько контейнеров и обертку, которая бы переключалась между ними smile
Кстати, может стоит посмотреть в сторону HeshSet? Говорят он может хранить почти 90 млн. записей. Но не уверен, что мне хватит smile

И почему я не начал писать это приложение на C++?!   smile 

Это сообщение отредактировал(а) SCAR - 23.7.2013, 22:08
PM MAIL   Вверх
SCAR
Дата 23.7.2013, 22:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Взвесил все "за" и "против", решил пока не смотреть на базу, а сделать фильтрацию моделей "на лету". Перед добавлением в словарь буду проверять на соответствие определенным критериям и если по ним модель не подходит, то добавлять ее не буду. Хотя планировал сделать данную фильтрацию после добавления всех моделей. Надеюсь в этом случае все поместится smile

А не подскажите, есть ли в C# какой-нить аналог std::remove_copy_if (С++) для generic контейнеров? 
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
mr.DUDA
THandle

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


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

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


 




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


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

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