如何独立调试Python线程?(WinPDB)

8 投票
1 回答
1241 浏览
提问于 2025-04-16 02:23

我正在用WinPDB调试Python程序,里面有多个线程是通过threading.Thread创建的。可我总是无法单独控制这些线程。如果我中断执行,整个脚本都会停止。如果我在一个线程的源代码中逐步调试,其他线程却会继续执行,互相交错。这种情况在同步功能开启或关闭时都是如此。难道没有办法在保持其他线程在断点的情况下,单独逐步调试一个线程吗?

使用WinPDB是不是不太合适?我真的不知道该用什么工具。Eclipse的PyDev几乎完全无法使用,因为调试器在启动多个线程时似乎会出现竞争错误。

有没有什么工具可以真正有效地调试一个多线程的Python程序?

谢谢。

1 个回答

1

我遇到过类似的问题,这不是最理想的解决办法,但我可以给你描述一下,也许你能从中得到一些启发。

我大致上写了一个迷你调试器。它包含了一个UDP客户端和服务器,还有一个函数,这个函数的作用就是获取一个全局锁,暂停0.1秒,然后再释放这个锁。这个函数被传递给每个线程。然后我在我想要调试的关键区域之间调用这个函数。启动程序后,UDP服务器会监听客户端,如果我输入“pause”,它就会获取那个共享函数使用的全局锁,并且在我输入“play”之前不会释放这个锁。通过这种方式,你可以在应用程序中实现比较精确的暂停……这取决于具体的应用。

希望这对你有帮助……下面是一个小片段。我的应用是为了测试平台,所以我在基类构造函数中添加了这个函数指针,使用它代替了time.sleep(),这样就能稍微调试一下。你可以把这个函数传递给每个线程,并在你的函数开始和结束时添加对暂停函数的调用,这样就可以实现中断等功能。我删除了一些命令,但你可以看到,这个方法可以根据需要扩展。

PAUSE_NOW     = thread.allocate_lock()
def pause(s):
'''
    FUNCTION: testStatus

    DESCRIPTION: function passed to all test objects

    INPUTS: none

    RETURNS: none
'''
    global Pause_NOW
    PAUSE_NOW.acquire()
    time.sleep(s)
    PAUSE_NOW.release()

`

def server():
    '''
        \r\n
        FUNCTION: server

        DESCRIPTION: UDP server that launches a UDP client. The client it
                     starts can issue commands defined in cmdlineop. Most
                     functions return a status, but some are meant to block
                     the main thread as a means of pausing a test, in which case
                     a default response is returned.

        INPUTS: none

        RETURNS: none
    '''
    global EXIT
    global Pause_NOW

    host = "localhost"
    port = 21567
    buf  = 1024
    addr = (host,port)

    UDPSock = socket(AF_INET,SOCK_DGRAM)
    UDPSock.bind(addr)
    sleep(1)
    os.startfile('client.py')
    #os.system('start python client.py')
    cmdlineop   =   {
                    'pausenow' : "PAUSE_NOW.acquire()",
                    'playnow'  : "PAUSE_NOW.release()",
                }
    while 1:
        output = 'RECEIVED CMD'
        # if EXIT: break
        data,addr = UDPSock.recvfrom(buf)
        if not data:
            break
        else:
            if cmdlineop.has_key(data.split()[0]):
                exec(cmdlineop[(data.split()[0])])
                UDPSock.sendto(('\n'+output+'\n'),addr)
                data = ''
            else:
                UDPSock.sendto('INVALID CMD',addr)
    UDPSock.close()

撰写回答