| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Для новичков > Проблема с логикой в цикле с выходом по условию |
| Автор: SABROG 30.7.2009, 21:24 | ||||
Есть такой рабочий код:
Выглядит он, мягко говоря, кривовато. По сути это основной цикл StAX парсера. Проблема в следующем. С целью оптимизации создал 2 вложенных цикла. Раньше проверка isCritical() шла на каждом витке цикла. Профайлер четко мне сказал, что этот метод один из самых жрущих процессорное время. Метод atEnd() возвращает true в двух случаях: достиг конец документа (все ОК) и возникла ошибка. Ошибка может быть не критической, после которой возможно продолжение цикла, просто добавляется новая порция данных для парсинга. Т.е. теперь внутренний цикл выполняется без проверки на ошибку каждый раз. А если она возникает, то идет выход (atEnd) из внутреннего цикла во внешний. К сожалению в C++ нет метода типа ::break, чтобы выйти сразу из всех вложенных циклов. Пришлось вставить костыль в виде булевой переменной flag. По началу я впихнул проверку этой переменной наряду с isCritical таким образом:
Проблема возникла в особенности языка 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 - или написать условие в одну строку, которое могло бы заставить компилятор проверять второе условие независимо от результатов проверки первого. |
| Автор: GoldFinch 30.7.2009, 21:44 |
| для выхода из 2х циклов сразу используйте return |
| Автор: mes 30.7.2009, 22:07 |
| если не сложно приведите первоначальный вариант парсера, мне кажется так будет легче помочь Вам правильно соптимизировать Ваш цикл. |
| Автор: ISergeyN 30.7.2009, 22:30 | ||
Наверно один из случаев когда можно использовать goto |
| Автор: SABROG 30.7.2009, 22:52 | ||||
azesmcar, спасибо. Окончательный вариант получился таким:
Это мне тогда придется выносить цикл while в отдельный метод, т.к. после цикла идет еще код, а он не выполнится, если я выйду по return.
Первоначального не существует как такового, по крайней мере для Qt, где всё на словах в документации, а примеры довольно примитивные. Примеры на Java можно посмотреть тут http://www.cafeconleche.org/slides/sd2004west/stax/StAX.html , только вот они тоже очень уж примитивные. Как минимум там нет реализации того, что является главным достоинством StAX'a - поточности. А именно не реализован механизм догрузки данных с последующим продолжением парсинга. Именно на это нацелены эти 2 цикла. Когда данных не хватает (битый, частично загруженный xml) приходит ошибка. По сути ошибка не критичная и метод isCritical() проверяет характер ошибки и вызывает метод догрузки или ожидания новых данных. Если в процессе ожидания пользователь отменил дальнейший парсинг или пропала связь с сервером, то isCritical вернет true. Если новые данные были получены, то возвращается false и цикл продолжается дальше. Хотелось бы услышать еще мнения ЗА goto от других людей. |
| Автор: mes 31.7.2009, 00:53 | ||||||||
насколько понял Вам нужно прекратить цикл когда сработает одно из 3х условий:
ну так одна функция и не должна решать больше одной проблемы имелся ввиду парсер до начала Вашей оптимизации. отдайте предпочтение разбиению на функции - уверен, что не пожалеете. |
| Автор: azesmcar 31.7.2009, 07:00 | ||
| SABROG По поводу goto http://forum.vingrad.ru/forum/topic-251118/0.html
Я бы перенес !flag на первое место, !isCritical() самая медленная проверка, пусть в первую очередь проверяется !flag, хотя это может избавить только от одного вызова IsCritical(), но все равно.. Мелочь а приятно |
| Автор: SABROG 31.7.2009, 08:42 |
| Да, я сам накосячил. Пробовал эти варианты, только у меня не было выхода по третьему условию (token != QXmlStreamReader::EndDocument). Весь мозг сломал почему не выходит из цикла Ты же вроде сам был против, поменял мнение? Пока сделал отдельный метод. Может его сделать inline, чтобы особо не влияло на скорость парсинга или компилер сам позаботится об этом |
| Автор: azesmcar 31.7.2009, 08:53 | ||||
Где я это говорил? Я сказал
Я лично никогда его не использовал, но там есть то что ты просил а именно, много мнений Добавлено через 1 минуту и 57 секунд
А сейчас медленно работает? Если нет - то зачем об этом думать? Скорость устраивает - все отлично, продолжай работать. Думать будешь об этом тогда, когда работать будет медленее чем ты от него ожидаешь. А так просто - оптимизация ради оптимизации зло. |
| Автор: bsa 31.7.2009, 17:13 |
| Лично я считаю выход из вложенного цикла одним из случаев, когда использовать goto целесообразно. Так как введение дополнительного флага это уже пессимизация. |
| Автор: mes 31.7.2009, 17:38 | ||
ага, особенно если флаг притянут к логике цикла за уши. но все таки, учитывая предрасположения топик стартера (как мне они покзались, судя по этой теме) и мои опасения, что он может сделать не очень верные выводы добавлю: Не бойтесь разбивать на функции, и Вам будет удобнее, и компилятору и линкеру легче оптимизировать Ваш код - гораздо легче, чем если будете использовать гото. P.S. если в методе не используется this для успокоения души можете делать такой метод статическим. |
| Автор: SABROG 31.7.2009, 20:40 | ||
Вот эта фраза.
Ну да ладно, я в любом случае последовал совету mes'a. Оценил также совет bsa и сделал вывод, что в принципе в такой ситуации можно воспользоваться goto, но предпочту этого не делать, чтобы не вырабатывать в себе плохую привычку ;) Работать будет в любом случае медленно. На php парсинг того объема xml данных, что через меня проходит каждый день занимает минимум 30-40 минут в день (сам процесс парсинга). Обычно в сумме это где-то 300-400Мб. Когда я пытался в последний раз парсить это дело на C++ через DOM, то на это уходило минут 5. Не критично, но ведь не быстро. Думаю вопрос решен. |