Как я могу сказать, где висит мой скрипт на python? - PullRequest
45 голосов
/ 09 августа 2010

Итак, я отлаживаю свою программу на Python и обнаружил ошибку, из-за которой программа зависает, как будто в бесконечном цикле. Теперь у меня была проблема с бесконечным циклом, но когда он зависал, я мог убить программу, и Python выплыл полезное исключение, которое сообщало мне, где программа остановилась, когда я послал ей команду kill. Однако теперь, когда программа зависает, и я нажимаю ctrl-c, она не прерывается, а продолжает работать. Есть ли какой-нибудь инструмент, который я могу использовать, чтобы найти трубку? Я новичок в профилировании, но насколько я знаю, профилировщик может предоставить вам только информацию о программе, которая успешно завершена. Или вы можете использовать профилировщик для отладки таких зависаний?

Ответы [ 12 ]

87 голосов
/ 10 августа 2010

Предположим, что вы запускаете вашу программу как:

python YOURSCRIPT.py

Попробуйте запустить вашу программу как:

python -m trace --trace YOURSCRIPT.py

И наберитесь терпения, пока на экране выводится много материала,Если у вас есть бесконечный цикл, он будет продолжаться вечно (проблема остановки).Если он где-то застрял, то в основном вы застряли на вводе-выводе или это тупик.

26 голосов
/ 10 августа 2010

Вау! Уже 5 ответов, и никто не предложил самое очевидное и простое:

  1. Попробуйте найти воспроизводимый контрольный пример, который вызывает зависание.
  2. Добавьте запись в ваш код. Это может быть так же просто, как print "**010", print "**020" и т. Д., Пронизывающих основные области.
  3. Выполнить код. Посмотрите, где это висит. Не могу понять почему? Добавьте больше регистрации. (Т.е. если между ** 020 и ** 030, перейдите и добавьте ** 023, ** 025, ** 027 и т. Д.)
  4. Перейти к 3.

Дети в наши дни со своими модными отладчиками и IDE ... Иногда инженерные проблемы решаются проще всего с помощью грубых инструментов, которые предоставляют чуть больше информации.

9 голосов
/ 10 августа 2010

Если ваша программа слишком большая и сложная, чтобы ее можно было использовать для пошагового выполнения с помощью pdb или печати каждой строки с помощью модуля trace, тогда вы можете попробовать хитрость из моих дней программирования 8-битных игр.Начиная с Python 2.5 и далее, pdb может связывать код с точкой останова с помощью команды commands.Вы можете использовать это для печати сообщения и продолжения работы:

(Pdb) commands 1
(com) print "*** Breakpoint 1 ***"
(com) continue
(com) end
(Pdb)

Это напечатает сообщение и продолжит работу при достижении точки останова 1.Определите аналогичные команды для нескольких других точек останова.

Вы можете использовать это для своего рода двоичного поиска вашего кода.Установите точки останова в ключевых местах кода и запускайте его до тех пор, пока он не зависнет.Вы можете узнать по последнему сообщению, которое было последней точкой останова.Затем вы можете переместить другие точки останова и повторно выполнить, чтобы сузить место в коде, где он висит.Промойте и повторите.

Между прочим, на 8-битных микросхемах (Commodore 64, Spectrum и т. Д.) Вы можете вставить значение в область реестра, чтобы изменить цвет границы вокруг экрана.Раньше я устанавливал несколько точек останова, чтобы сделать это разными цветами, поэтому, когда программа запускалась, она отображала психоделическую радугу до тех пор, пока она не зависла, тогда граница изменилась на один цвет, который говорил вам, какой была последняя точка останова.Вы также можете почувствовать относительную производительность различных разделов кода по количеству каждого цвета в радуге.Иногда я скучаю по этой простоте в этих новых "Windows" машинах.

7 голосов
/ 19 июля 2013

Я написал модуль, который печатает темы, которые зависают дольше 10 секунд в одном месте. hang_threads.py

Вот пример выходных данных:

--------------------    Thread 5588     --------------------
  File "C:\python33\lib\threading.py", line 844, in _exitfunc
        t.join()
  File "C:\python33\lib\threading.py", line 743, in join
        self._block.wait()
  File "C:\python33\lib\threading.py", line 184, in wait
        waiter.acquire()

Это происходит при выходе из основного потока, когда вы забыли установить другой поток в качестве демона.

3 голосов
/ 24 февраля 2017

Если ваша программа слишком сложна, чтобы просто отследить все функции, вы можете попробовать запустить ее и вручную присоединить к ней программу трассировки, например lptrace . Он работает немного как strace - он печатает каждую функцию, которую вызывает ваша программа. Вот как это назвать:

python lptrace -p $STUCK_PROGRAM_PID

Обратите внимание, что для запуска lptrace требуется gdb.

3 голосов
/ 09 августа 2010

Проще предотвратить эти зависания, чем отладить их.

Во-первых: for петли очень и очень трудно застрять в ситуации, когда цикл не завершится. Очень сложно.

Второй: while петли относительно легко застрять в петле.

Первый проход - проверка каждого цикла while, чтобы определить, должен ли он быть циклом while. Часто вы можете заменить while конструкции на for, и вы исправите свою проблему, переосмыслив свой цикл.

Если вы не можете заменить цикл while на for, то вам просто нужно доказать, что выражение в операторе while должно каждый раз изменяться в цикле. Это не так сложно доказать.

  1. Посмотрите на все условия в цикле. Назовите это T .

  2. Посмотрите на все логические ветви в теле цикла. Есть ли способ пройти через цикл, не внося изменений в условие, T ?

    • Да? Это твоя ошибка. Этот логический путь неверен.

    • Нет? Отлично, этот цикл должен завершиться.

2 голосов
/ 18 июля 2011

Вы также можете попробовать http://code.activestate.com/recipes/576515-debugging-a-running-python-process-by-interrupting/.Он должен работать до тех пор, пока у процесса Python нет маскируемых сигналов, что обычно имеет место, даже если Ctrl-C не работает.

2 голосов
/ 09 августа 2010

Ничего подобного старому доброму pdb

import pdb
pdb.run('my_method()',globals(),locals())

Затем просто нажмите (n), чтобы перейти к следующей команде, чтобы войтисм. документы для полной ссылки.Следуйте своей программе шаг за шагом, и вы, вероятно, поймете это достаточно быстро.

0 голосов
/ 20 мая 2017
i = 0
for t in threading.enumerate():
    if i != 0:# and t.getName() != 'Thread-1':
        print t.getName()
        t._Thread__stop()
    i += 1

Как только вы узнаете названия потоков; начать повторное выполнение вашего сценария и отфильтровать их, не останавливая их от прерывания. Условие i = 0 предотвращает прерывание основного потока.

Я предлагаю пройтись и назвать все ваши темы; такие как: Поток (target = self.log_sequence_status, name = 'log status')

Этот код должен находиться в конце основной программы, которая запускает процесс запуска

0 голосов
/ 10 августа 2010

Ух ты! Кажется, вы добавили столько кода за один раз, не тестируя его, что вы не можете сказать, какой код был добавлен непосредственно перед тем, как программа начала зависать ... (наиболее вероятная причина проблемы).

Серьезно, вы должны кодировать небольшими шагами и тестировать каждый в отдельности (в идеале - TDD).

Для вашей точной проблемы определения того, какой код Python выполняется и ctrl-c не работает, я попытаюсь сделать грубое предположение: вы использовали except:, перехватывая все исключения нечетко. Если вы сделали это в цикле (и продолжаете цикл после управления исключениями), вполне вероятно, что ctrl-c не работает: он перехватывается этим исключением. Измените на except Exception:, и он больше не должен быть перехвачен (есть другие возможности для ctrl + c не работать как управление потоками, как предложил другой автор, но я полагаю, что приведенная выше причина более вероятна).

исключение KeyboardInterrupt

Raised when the user hits the interrupt key (normally Control-C or Delete). 

Во время выполнения регулярно проверяется наличие прерываний. Прерывания, которые вводятся, когда встроенная функция input () или raw_input () ожидание ввода также поднять это исключение. Исключение наследует из BaseException, чтобы случайно не быть пойманным кодом, который ловит Exception и, таким образом, препятствует выходу интерпретатора.

Changed in version 2.5: Changed to inherit from BaseException.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...