我怎么知道我的python脚本挂在哪里?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3443607/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 11:08:15  来源:igfitidea点击:

How can I tell where my python script is hanging?

pythondebugging

提问by Johnny

So I'm debugging my python program and have encountered a bug that makes the program hang, as if in an infinite loop. Now, I had a problem with an infinite loop before, but when it hung up I could kill the program and python spat out a helpful exception that told me where the program terminated when I sent it the kill command. Now, however, when the program hangs up and I ctrl-c it, it does not abort but continues running. Is there any tool I can use to locate the hang up? I'm new to profiling but from what I know a profiler can only provide you with information about a program that has successfully completed. Or can you use a profiler to debug such hang ups?

所以我在调试我的 python 程序时遇到了一个使程序挂起的错误,就像处于无限循环中一样。现在,我之前遇到了一个无限循环的问题,但是当它挂断时,我可以终止程序,python 吐出一个有用的异常,告诉我当我向它发送 kill 命令时程序在哪里终止。但是,现在,当程序挂断并按 ctrl-c 时,它不会中止而是继续运行。有什么工具可以用来定位挂断电话吗?我是分析的新手,但据我所知,分析器只能为您提供有关已成功完成的程序的信息。或者您可以使用分析器来调试此类挂断吗?

回答by Matti Lyra

Haven't used it myself but I've heard that the Eric IDEis good and has a good debugger. That's also the only IDE I know of that has a debugger for Python

我自己没有使用过,但我听说Eric IDE很好并且有一个很好的调试器。这也是我所知道的唯一一个带有 Python 调试器的 IDE

回答by Ofri Raviv

Nothing like the good old pdb

没有什么比好的旧pdb

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

Then just hit (n) to go to the next command, (s) to step into. see the docs for the full reference. Follow your program step by step, and you'll probably figure it out fast enough.

然后只需按 (n) 转到下一个命令, (s) 即可进入。有关完整参考,请参阅文档。按照你的程序一步一步来,你可能会很快弄清楚。

回答by S.Lott

It's easier to prevent these hang-ups than it is to debug them.

防止这些挂断比调试它们更容易。

First: forloops are very, very hard to get stuck in a situation where the loop won't terminate. Very hard.

首先:for循环非常非常难以陷入循环不会终止的情况。很难。

Second: whileloops are relatively easy to get stuck in a loop.

第二:while循环相对容易陷入循环。

The first pass is to check every whileloop to see if it mustbe a whileloop. Often you can replace whileconstructs with for, and you'll correct your problem by rethinking your loop.

第一遍是检查每个while循环,看它是否一定是一个while循环。通常,您可以用 替换while结构for,然后通过重新思考循环来纠正问题。

If you cannot replace a whileloop with for, then you simply have to prove that the expression in the whilestatement mustchange every time through the loop. This isn't that hard to prove.

如果您不能用 替换while循环for,那么您只需证明while语句中的表达式在每次循环中都必须改变。这并不难证明。

  1. Look at all the condition in the loop. Call this T.

  2. Look at all the logic branches in the body of the loop. Is there any way to get through the loop without making a change to the condition, T?

    • Yes? That's your bug. That logic path is wrong.

    • No? Excellent, that loop mustterminate.

  1. 查看循环中的所有条件。称其为T

  2. 查看循环体中的所有逻辑分支。有没有办法在不改变条件T的情况下通过循环?

    • 是的?那是你的错误。那条逻辑路径是错误的。

    • 不?太好了,该循环必须终止。

回答by phlip

If your program has more than one thread, it could be ignoring ctrl-c because the one thread is wired up to the ctrl-c handler, but the live (runaway?) thread is deaf to it. The GIL (global interpreter lock) in CPython means that normally only one thread can actually be running at any one time. I think I solved my (perhaps) similar problem using this

如果您的程序有多个线程,它可能会忽略 ctrl-c,因为一个线程连接到 ctrl-c 处理程序,但活动(失控?)线程对其充耳不闻。CPython 中的 GIL(全局解释器锁)意味着通常在任何时候实际上只有一个线程可以运行。我想我用这个解决了我的(也许)类似的问题

回答by dhruvbird

Let's assume that you are running your program as:

让我们假设您正在运行您的程序:

python YOURSCRIPT.py

Try running your program as:

尝试将您的程序运行为:

python -m trace --trace YOURSCRIPT.py

And have some patience while lots of stuff is printed on the screen. If you have an infinite loop, it will go on for-ever (halting problem). If it gets stuck somewhere, then mostly you are stuck on I/O or it is a deadlock.

并且在屏幕上打印很多东西时要有一些耐心。如果您有一个无限循环,它将永远持续下去(停止问题)。如果它卡在某个地方,那么大多数情况下你会卡在 I/O 上或者是一个死锁。

回答by dkamins

Wow! 5 answers already and nobody has suggested the most obvious and simple:

哇!已经有 5 个答案,没有人提出最明显和最简单的答案:

  1. Try to find a reproducible test case that causes the hanging behavior.
  2. Add logging to your code. This can be as basic as print "**010", print "**020", etc. peppered through major areas.
  3. Run code. See where it hangs. Can't understand why? Add more logging. (I.e. if between **020 and **030, go and add **023, **025, **027, etc.)
  4. Goto 3.
  1. 尝试找到导致挂起行为的可重现测试用例。
  2. 将日志记录添加到您的代码中。这可以像、 等一样基本print "**010"print "**020"贯穿主要区域。
  3. 运行代码。看看它挂在哪里。不明白为什么?添加更多日志记录。(即如果在 **020 和 **030 之间,请添加 **023、**025、**027 等)
  4. 转到 3。

回答by Dave Kirby

If your program is too big and complex to be viable for single stepping with pdb or printing every line with the trace module then you could try a trick from my days of 8-bit games programming. From Python 2.5 onwards pdb has the ability to associate code with a breakpoint by using the commandscommand. You can use this to print a message and continue running:

如果您的程序太大而复杂,无法使用 pdb 单步执行或使用跟踪模块打印每一行,那么您可以尝试使用我在 8 位游戏编程时代的技巧。从 Python 2.5 开始,pdb 能够使用commands命令将代码与断点相关联。您可以使用它来打印一条消息并继续运行:

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

This will print a message and carry on running when breakpoint 1 is hit. Define similar commands for a few other breakpoints.

当断点 1 被击中时,这将打印一条消息并继续运行。为其他几个断点定义类似的命令。

You can use this to do a kind of binary search of your code. Attach breakpoints at key places in the code and run it until it hangs. You can tell from the last message which was the last breakpoint it hit. You can then move the other breakpoints and re-run to narrow down the place in the code where it hangs. Rinse and repeat.

您可以使用它对您的代码进行一种二进制搜索。在代码中的关键位置附加断点并运行它直到它挂起。您可以从最后一条消息中知道哪个是它击中的最后一个断点。然后您可以移动其他断点并重新运行以缩小代码中它挂起的位置。冲洗并重复。

Incidentally on the 8-bit micros (Commodore 64, Spectrum etc) you could poke a value into a registry location to change the colour of the border round the screen. I used to set up a few breakpoints to do this with different colours, so when the program ran it would give a psychedelic rainbow display until it hung, then the border would change to a single colour that told you what the last breakpoint was. You could also get a good feel for the relative performance of different sections of code by the amount of each colour in the rainbow. Sometimes I miss that simplicity in these new fangled "Windows" machines.

顺便说一句,在 8 位微型计算机(Commodore 64、Spectrum 等)上,您可以将一个值插入注册表位置以更改屏幕周围边框的颜色。我曾经设置了几个断点来用不同的颜色来做这件事,所以当程序运行时,它会显示出迷幻的彩虹,直到它挂起,然后边框会变成单一颜色,告诉你最后一个断点是什么。通过彩虹中每种颜色的数量,您还可以很好地了解不同代码部分的相对性能。有时我会怀念这些新式“Windows”机器的简单性。

回答by kriss

Wow ! Seems you added so much code in one go without testing it that you can't say what code was added just before program started to hang... (the most likely cause of problem).

哇 !似乎您一次添加了这么多代码而没有对其进行测试,以至于您无法说出在程序开始挂起之前添加了哪些代码......(最可能的问题原因)。

Seriously, you should code by small steps and test each one individually (ideally doing TDD).

说真的,您应该分步编写代码并单独测试每个步骤(最好是 TDD)。

For your exact problem of spotting what python code is running and ctrl-c does not work, I will try a raw guess: did you used some except:catching all exceptions indistinctly. If you did so in a loop (and continue loop after managing exception), it's a very likely reason why ctrl-c does not work : it's catched by this exception. Change to except Exception:and it should not be catched any more (there is other possibilities for ctrl+c not working like thread management as another poster suggested, but I believe the above reason is more likely).

对于您发现正在运行的 python 代码和 ctrl-c 不起作用的确切问题,我将尝试一个原始猜测:您是否使用了一些except:模糊地捕获所有异常。如果您在循环中这样做(并在管理异常后继续循环),这很可能是 ctrl-c 不起作用的原因:它被此异常捕获。更改为except Exception:并且不应再被捕获(还有其他可能性 ctrl+c 不像另一个海报建议的线程管理那样工作,但我相信上述原因更有可能)。

exception KeyboardInterrupt

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

During execution, a check for interrupts is made regularly. Interrupts typed when a built-in function input() or raw_input() is waiting for input also raise this exception. The exception inherits from BaseException so as to not be accidentally caught by code that catches Exception and thus prevent the interpreter from exiting.

Changed in version 2.5: Changed to inherit from BaseException.

异常键盘中断

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.

回答by Daira Hopwood

You could also try http://code.activestate.com/recipes/576515-debugging-a-running-python-process-by-interrupting/. It should work as long as the Python process doesn't have signals masked, which is normally the case even if Ctrl-C doesn't work.

您也可以尝试http://code.activestate.com/recipes/576515-debugging-a-running-python-process-by-interrupting/。只要 Python 进程没有屏蔽信号,它就应该可以工作,即使 Ctrl-C 不起作用,通常也是这种情况。

回答by User

I wrote a module that prints out threads that hang longer that 10 seconds at one place. hanging_threads.py

我编写了一个模块,可以打印出在一个地方挂起时间超过 10 秒的线程。 挂线程.py

Here is an example output:

这是一个示例输出:

--------------------    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()

This occurs at the exit of the main thread when you forget to set another thread as daemon.

当您忘记将另一个线程设置为守护进程时,这会在主线程退出时发生。