用pdb附加一个进程 [英] Attaching a process with pdb

查看:181
本文介绍了用pdb附加一个进程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个python脚本,我怀疑有一个僵局。我试图用 pdb 进行调试,但是如果我一步一步地进行调试,它不会得到死锁,并且返回的输出可以看出它没有被挂在相同的迭代我想把脚本附加到调试器,只有当它被锁定,是可能吗?如果需要,我可以使用其他调试器。

解决方案

此时, pdb 不有能力在正在运行的程序上停止并开始调试。您还有一些其他选项:



GDB



您可以使用GDB在C级调试。这是一个更抽象的,因为你在Python的C源代码,而不是你的实际的Python脚本,但它可能对某些情况有用。说明如下: https://wiki.python.org/moin/DebuggingWithGdb 。他们太参与了这里的总结。



第三方扩展和模块



只需搜索pdb attach过程即可显示几个项目,以便PDB提供此功能:

Pyringe: https://github.com/google/pyringe

Pycharm: https://blog.jetbrains.com/pycharm / 2015/02 / feature-Spotlight-python-debugger-and-attach-to-process /

这个Python wiki的页面有几个选择: https://wiki.python.org/moin/PythonDebuggingTools






对于您的具体用例,我有一些解决方法的想法:



信号



如果您使用unix,可以使用信号,如这个博文试图停止并附加到正在运行的脚本。



此引用块直接从链接的博文中复制:


当然pdb已经有函数要启动程序中间的一个调试器,最着名的是pdb.set_trace()。然而,这需要你知道你想要开始调试的地方,这也意味着你不能把它放在生产代码中。



但是我一直很羡慕我可以用GDB做什么:只是中断一个正在运行的程序,并开始用一个调试器。这在某些情况下可以方便,例如你被困在一个循环中,想要调查。今天突然发生在我身上:只需注册一个设置跟踪功能的信号处理程序!这里的概念代码证明:

  import os 
import signal
import sys
import时间

def handle_pdb(sig,frame):
import pdb
pdb.Pdb()。set_trace(frame)

def loop():
while True:
x ='foo'
time.sleep(0.2)

如果__name__ =='__main__':
signal.signal .SIGUSR1,handle_pdb)
print(os.getpid())
loop()

现在我可以发送SIGUSR1到正在运行的应用程序,并得到一个调试器。可爱!



我想象您可以通过使用Winpdb来调用它,以便在您的应用程序不再附加到终端的情况下进行远程调试。而上述代码的另一个问题是,在pdb被调用后似乎无法恢复程序,在退出pdb之后,只需要获取一个追溯并完成(但是由于这只是bdb提升了bdb.BdbQuit异常我猜这可以通过几种方式解决)。最后一个直接的问题是在Windows上运行,我不太了解Windows,但我知道他们没有信号,所以我不知道你可以这样做。




条件断点和循环



您仍然可以使用PDB如果您没有可用的信号,如果您将锁或信号量采集包含在增加计数器的循环中,并且只有当计数达到可笑的数量时才停止。例如,假设你有一个锁,你怀疑是你的死锁的一部分:

  lock.acquire()#一些锁或信号量从线程或多处理

以这种方式重写:

  count = 0 
while not lock.acquire(False):#启动一个循环,如果死锁
count + = 1

continue#现在在PDB中设置条件断点,只有当
#count是一个可笑的大数字时才会触发:
#pdb> < filename:linenumber> count = 9999999999

当计数非常大时,断点应触发, (希望)表明在那里发生了僵局。如果发现锁定对象似乎没有指示死锁时触发,那么您可能需要在循环中插入一个短时间的延迟,因此它不会如此快速地增长。您也可能需要使用断点触发阈值,以便在适当的时间触发。我的例子中的数字是任意的。



另一个变体就是不使用PDB,有意在计数器变大时引发异常,而不是触发断点。如果您编写自己的异常类,可以使用它来将异常中的所有本地信号量/锁定状态进行捆绑,然后在脚本的顶层捕获它,以便在退出之前打印出来。



文件指标



不同的方式可以使用你的死锁循环,而不依赖于获取计数器的权限是写入文件:

  import time 

while not lock.acquire(False):#启动一个循环,无限如果死锁
与open('checkpoint_a.txt','a')为fo:#打开一个唯一的文件名
fo.write(\\\
Hit)#写入指针到文件
time.sleep(3)#暂停一会,所以文件大小不会爆炸

现在让你的程序运行一两分钟。杀死程序并通过这些检查点文件。如果僵局对您的停滞程序负责,那么多次写入打字样的文件表明哪些锁收购对您的死锁负责。



您可以通过使循环打印变量或其他状态信息而不是仅仅是一个常量来扩展它的有用性。例如,你说你怀疑死锁发生在一个循环中,但不知道它是什么迭代。有这个锁循环转储您的循环的控制变量或其他状态信息,以确定发生死锁的迭代。


I have a python script that I suspect that there is a deadlock. I was trying to debug with pdb but if I go step by step it doesn't get the deadlock, and by the output returned I can see that it's not being hanged on the same iteration. I would like to attach my script to a debugger only when it gets locked, is it possible? I'm open to use other debuggers if necessary.

解决方案

At this time, pdb does not have the ability to halt and begin debugging on a running program. You have a few other options:

GDB

You can use GDB to debug at the C level. This is a bit more abstract because you're poking around Python's C source code rather than your actual Python script, but it can be useful for some cases. The instructions are here: https://wiki.python.org/moin/DebuggingWithGdb. They are too involved to summarise here.

Third-Party Extensions & Modules

Just googling for "pdb attach process" reveals a couple of projects to give PDB this ability:
Pyringe: https://github.com/google/pyringe
Pycharm: https://blog.jetbrains.com/pycharm/2015/02/feature-spotlight-python-debugger-and-attach-to-process/
This page of the Python wiki has several alternatives: https://wiki.python.org/moin/PythonDebuggingTools


For your specific use case, I have some ideas for workarounds:

Signals

If you're on unix, you can use signals like in this blog post to try to halt and attach to a running script.

This quote block is copied directly from the linked blog post:

Of course pdb has already got functions to start a debugger in the middle of your program, most notably pdb.set_trace(). This however requires you to know where you want to start debugging, it also means you can't leave it in for production code.

But I've always been envious of what I can do with GDB: just interrupt a running program and start to poke around with a debugger. This can be handy in some situations, e.g. you're stuck in a loop and want to investigate. And today it suddenly occurred to me: just register a signal handler that sets the trace function! Here the proof of concept code:

import os
import signal
import sys
import time    

def handle_pdb(sig, frame):
    import pdb
    pdb.Pdb().set_trace(frame)    

def loop():
    while True:
        x = 'foo'
        time.sleep(0.2)

if __name__ == '__main__':
    signal.signal(signal.SIGUSR1, handle_pdb)
    print(os.getpid())
    loop()

Now I can send SIGUSR1 to the running application and get a debugger. Lovely!

I imagine you could spice this up by using Winpdb to allow remote debugging in case your application is no longer attached to a terminal. And the other problem the above code has is that it can't seem to resume the program after pdb got invoked, after exiting pdb you just get a traceback and are done (but since this is only bdb raising the bdb.BdbQuit exception I guess this could be solved in a few ways). The last immediate issue is running this on Windows, I don't know much about Windows but I know they don't have signals so I'm not sure how you could do this there.

Conditional Breakpoints and Loops

You may still be able to use PDB if you don't have signals available, if you wrap your lock or semaphore acquisitions in a loop that increments a counter, and only halt when the count has reached a ridiculously large number. For example, say you have a lock that you suspect is part of your deadlock:

lock.acquire() # some lock or semaphore from threading or multiprocessing

Rewrite it this way:

count = 0
while not lock.acquire(False): # Start a loop that will be infinite if deadlocked
    count += 1

    continue # now set a conditional breakpoint here in PDB that will only trigger when
             # count is a ridiculously large number:
             # pdb> <filename:linenumber>, count=9999999999

The breakpoint should trigger when when count is very large, (hopefully) indicating that a deadlock has occurred there. If you find that it's triggering when the locking objects don't seem to indicate a deadlock, then you may need to insert a short time delay in the loop so it doesn't increment quite so fast. You also may have to play around with the breakpoint's triggering threshold to get it to trigger at the right time. The number in my example was arbitrary.

Another variant on this would be to not use PDB, and intentionally raise an exception when the counter gets huge, instead of triggering a breakpoint. If you write your own exception class, you can use it to bundle up all of the local semaphore/lock states in the exception, then catch it at the top-level of your script to print out right before exiting.

File Indicators

A different way you can use your deadlocked loop without relying on getting counters right would be to write to files instead:

import time

while not lock.acquire(False): # Start a loop that will be infinite if deadlocked
    with open('checkpoint_a.txt', 'a') as fo: # open a unique filename
        fo.write("\nHit") # write indicator to file
        time.sleep(3)     # pause for a moment so the file size doesn't explode

Now let your program run for a minute or two. Kill the program and go through those "checkpoint" files. If deadlock is responsible for your stalled program, the files that have the word "hit" written in them a bunch of times indicate which lock acquisitions are responsible for your deadlock.

You can expand the usefullness of this by having the loop print variables or other state information instead of just a constant. For example, you said you suspect the deadlock is happening in a loop but don't know what iteration it's on. Have this lock loop dump your loop's controlling variables or other state information to identify the iteration the deadlock occured on.

这篇关于用pdb附加一个进程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆