Модераторы: bsa
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Проблема с логикой в цикле с выходом по условию 
V
    Опции темы
SABROG
  Дата 30.7.2009, 21:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Hacker
****


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

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



Есть такой рабочий код:

Код

bool flag = false;
    do {
        while (!xml->atEnd()){
            token = xml->readNext();

            if (implementation()) {
                flag = true;
                break;
            }
        }
        if (flag || token == QXmlStreamReader::EndDocument) {
            break;
        }
    } while (!isCritical());


Выглядит он, мягко говоря, кривовато. По сути это основной цикл StAX парсера.

Проблема в следующем. С целью оптимизации создал 2 вложенных цикла. Раньше проверка isCritical() шла на каждом витке цикла. Профайлер четко мне сказал, что этот метод один из самых жрущих процессорное время. Метод atEnd() возвращает true в двух случаях: достиг конец документа (все ОК) и возникла ошибка. Ошибка может быть не критической, после которой возможно продолжение цикла, просто добавляется новая порция данных для парсинга. Т.е. теперь внутренний цикл выполняется без проверки на ошибку каждый раз. А если она возникает, то идет выход (atEnd) из внутреннего цикла во внешний. К сожалению в C++ нет метода типа ::break, чтобы выйти сразу из всех вложенных циклов. Пришлось вставить костыль в виде булевой переменной flag. По началу я впихнул проверку этой переменной наряду с isCritical таким образом:

Код

} while (!isCritical() || flag);


Проблема возникла в особенности языка C++. Если первое условие не выполняется, то второе условие не проверяется вообще. Пришлось проверку вынести  в if. Ума не приложу как в одну строчку написать такое условие:
- если flag не установлен (false), то выходим из всех циклов, при условии, что isCritical() вернет положительное значение (true), при том, что если flag все-таки установлен (true), то выходим из циклов не зависимо от того, что вернет isCritical().

(flag==true && isCritical()==true||false) - выход из циклов (метод isCritical() должен вызываться только один раз)
(flag==false && isCritical()==true) - выход из циклов (здесь метод isCritical() должен вызываться независимо от значения flag, т.к. происходящее внутри может на него повлиять при следующем витке, но как я говорил выше компилятор проверяет только первое условие, и если оно отрицательное, то второе условие не выполняется, что приводит к бесконечным итерациям.).

Итого проблемы 2:
- выход из двух вложенных циклов while без return или goto, отказавшись от проверки flag'a
- или написать условие в одну строку, которое могло бы заставить компилятор проверять второе условие независимо от результатов проверки первого.


--------------------
Национальная группа Russian Federation на QtCentre.
PM MAIL   Вверх
azesmcar
Дата 30.7.2009, 21:37 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


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

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



Цитата(SABROG @  30.7.2009,  21:24 Найти цитируемый пост)

Ума не приложу как в одну строчку написать такое условие:
- если flag не установлен (false), то выходим из всех циклов, при условии, что isCritical() вернет положительное значение (true), при том, что если flag все-таки установлен (true), то выходим из циклов не зависимо от того, что вернет isCritical().

Код

if ( flag || (!flag && isCritical()) ) ...


остальное как-то запутанно написано, или мне сильно спать хочется. smile 

Это сообщение отредактировал(а) azesmcar - 30.7.2009, 21:39
PM   Вверх
GoldFinch
Дата 30.7.2009, 21:44 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата



****


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

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



для выхода из 2х циклов сразу используйте return
PM MAIL ICQ   Вверх
mes
Дата 30.7.2009, 22:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


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

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



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



--------------------
PM MAIL WWW   Вверх
ISergeyN
Дата 30.7.2009, 22:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Цитата(SABROG @  30.7.2009,  21:24 Найти цитируемый пост)
 К сожалению в C++ нет метода типа ::break, чтобы выйти сразу из всех вложенных циклов.

Наверно один из случаев когда можно использовать goto  smile  
PM MAIL Skype   Вверх
SABROG
Дата 30.7.2009, 22:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Hacker
****


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

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



azesmcar, спасибо. Окончательный вариант получился таким:

Код

} while (((!flag && !isCritical()) || !flag) && (token != QXmlStreamReader::EndDocument));


Цитата(GoldFinch @  30.7.2009,  21:44 Найти цитируемый пост)
для выхода из 2х циклов сразу используйте return 


Это мне тогда придется выносить цикл while в отдельный метод, т.к. после цикла идет еще код, а он не выполнится, если я выйду по return.

Цитата(mes @  30.7.2009,  22:07 Найти цитируемый пост)
если не сложно приведите первоначальный вариант парсера, мне кажется так будет легче помочь Вам правильно соптимизировать Ваш цикл.


Первоначального не существует как такового, по крайней мере для Qt, где всё на словах в документации, а примеры довольно примитивные.

Примеры на Java можно посмотреть тут http://www.cafeconleche.org/slides/sd2004west/stax/StAX.html , только вот они тоже очень уж примитивные. Как минимум там нет реализации того, что является главным достоинством StAX'a - поточности. А именно не реализован механизм догрузки данных с последующим продолжением парсинга. Именно на это нацелены эти 2 цикла. Когда данных не хватает (битый, частично загруженный xml) приходит ошибка. По сути ошибка не критичная и метод isCritical() проверяет характер ошибки и вызывает метод догрузки или ожидания новых данных. Если в процессе ожидания пользователь отменил дальнейший парсинг или пропала связь с сервером, то isCritical вернет true. Если новые данные были получены, то возвращается false и цикл продолжается дальше.

Цитата(ISergeyN @  30.7.2009,  22:30 Найти цитируемый пост)
Наверно один из случаев когда можно использовать goto

Хотелось бы услышать еще мнения ЗА goto от других людей.


--------------------
Национальная группа Russian Federation на QtCentre.
PM MAIL   Вверх
mes
Дата 31.7.2009, 00:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


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

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



Цитата(SABROG @  30.7.2009,  21:52 Найти цитируемый пост)
Хотелось бы услышать еще мнения ЗА goto от других людей.


Цитата(SABROG @  30.7.2009,  21:52 Найти цитируемый пост)
    
Окончательный вариант получился таким:
Код

} while (((!flag && !isCritical()) || !flag) && (token != QXmlStreamReader::EndDocument));

насколько понял Вам нужно прекратить цикл когда сработает одно из 3х условий:
Код

while ((!isCritical() &&  !flag  && token != QXmlStreamReader::EndDocument);


Цитата(SABROG @  30.7.2009,  21:52 Найти цитируемый пост)
Это мне тогда придется выносить цикл while в отдельный метод, т.к. после цикла идет еще код, а он не выполнится, если я выйду по return.

ну так одна функция и не должна решать  больше одной проблемы  smile 

Цитата(SABROG @  30.7.2009,  21:52 Найти цитируемый пост)
Первоначального не существует как такового,

имелся ввиду парсер до начала Вашей оптимизации. smile

Цитата(SABROG @  30.7.2009,  21:52 Найти цитируемый пост)
Хотелось бы услышать еще мнения ЗА goto от других людей. 

отдайте предпочтение разбиению на функции - уверен, что не пожалеете. smile 





--------------------
PM MAIL WWW   Вверх
azesmcar
Дата 31.7.2009, 07:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


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

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



SABROG

По поводу goto http://forum.vingrad.ru/forum/topic-251118/0.html

Цитата(mes @  31.7.2009,  00:53 Найти цитируемый пост)
while ((!isCritical() &&  !flag  && token != QXmlStreamReader::EndDocument);

Я бы перенес !flag на первое место, !isCritical() самая медленная проверка, пусть в первую очередь проверяется !flag, хотя это может избавить только от одного вызова IsCritical(), но все равно.. Мелочь а приятно smile


Это сообщение отредактировал(а) azesmcar - 31.7.2009, 07:02
PM   Вверх
SABROG
Дата 31.7.2009, 08:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Hacker
****


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

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



Да, я сам накосячил. Пробовал эти варианты, только у меня не было выхода по третьему условию (token != QXmlStreamReader::EndDocument). Весь мозг сломал почему не выходит из цикла smile

Цитата(azesmcar @  31.7.2009,  07:00 Найти цитируемый пост)
По поводу goto

Ты же вроде сам был против, поменял мнение? smile http://forum.vingrad.ru/index.php?showtopi...t&p=1810869

Пока сделал отдельный метод. Может его сделать inline, чтобы особо не влияло на скорость парсинга или компилер сам позаботится об этом smile?


--------------------
Национальная группа Russian Federation на QtCentre.
PM MAIL   Вверх
azesmcar
Дата 31.7.2009, 08:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


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

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



Цитата(SABROG @  31.7.2009,  08:42 Найти цитируемый пост)
Ты же вроде сам был против, поменял мнение? 

Где я это говорил? Я сказал
Цитата(azesmcar @  14.3.2009,  08:28 Найти цитируемый пост)

если безопаснее и изящнее - нет проблем. Но я лично не встречал случая где его нужно было бы использовать и даже без стиля я бы много много раз подумал перед тем как оставить код с гото smile

Я лично никогда его не использовал, но там есть то что ты просил

Цитата(SABROG @  30.7.2009,  22:52 Найти цитируемый пост)
Хотелось бы услышать еще мнения ЗА goto от других людей. 

а именно, много мнений smile

Добавлено через 1 минуту и 57 секунд
Цитата(SABROG @  31.7.2009,  08:42 Найти цитируемый пост)
Пока сделал отдельный метод. Может его сделать inline, чтобы особо не влияло на скорость парсинга или компилер сам позаботится об этом smile? 

А сейчас медленно работает? Если нет - то зачем об этом думать? Скорость устраивает - все отлично, продолжай работать. Думать будешь об этом тогда, когда работать будет медленее чем ты от него ожидаешь. А так просто - оптимизация ради оптимизации зло.
PM   Вверх
bsa
Дата 31.7.2009, 17:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

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



Лично я считаю выход из вложенного цикла одним из случаев, когда использовать goto целесообразно. Так как введение дополнительного флага это уже пессимизация.
PM   Вверх
mes
Дата 31.7.2009, 17:38 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


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

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



Цитата(bsa @  31.7.2009,  16:13 Найти цитируемый пост)
Лично я считаю выход из вложенного цикла одним из случаев, когда использовать goto целесообразно. Так как введение дополнительного флага это уже пессимизация. 

ага, особенно если флаг притянут к логике цикла за уши. smile

но все таки, учитывая предрасположения топик стартера (как мне они покзались, судя по этой теме) и мои опасения, что он может сделать не очень верные выводы добавлю:
Не бойтесь разбивать на функции, и Вам будет удобнее, и компилятору и линкеру легче оптимизировать Ваш код - гораздо легче, чем если будете использовать гото.
 smile 

P.S. если в методе не используется this для успокоения души можете делать такой метод статическим. smile



Это сообщение отредактировал(а) mes - 31.7.2009, 17:39


--------------------
PM MAIL WWW   Вверх
SABROG
Дата 31.7.2009, 20:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Hacker
****


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

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



Цитата(azesmcar @  31.7.2009,  08:53 Найти цитируемый пост)
Где я это говорил?


Вот эта фраза. 

Цитата

может это считается пессимизацией, но по моему все равно лучше писать так чем гото


Ну да ладно, я в любом случае последовал совету mes'a. Оценил также совет bsa и сделал вывод, что в принципе в такой ситуации можно воспользоваться goto, но предпочту этого не делать, чтобы не вырабатывать в себе плохую привычку ;)

Цитата(azesmcar @  31.7.2009,  08:53 Найти цитируемый пост)
А сейчас медленно работает? Если нет - то зачем об этом думать?


Работать будет в любом случае медленно. На php парсинг того объема xml данных, что через меня проходит каждый день занимает минимум 30-40 минут в день (сам процесс парсинга). Обычно в сумме это где-то 300-400Мб. Когда я пытался в последний раз парсить это дело на C++ через DOM, то на это уходило минут 5. Не критично, но ведь не быстро.

Думаю вопрос решен.


--------------------
Национальная группа Russian Federation на QtCentre.
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


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

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


 




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


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

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