我可以在Python的后台线程上设置断点吗?
我正在使用Eclipse的PyDev插件,想在一些在后台线程中运行的代码里设置一个断点。但是这个断点从来没有被触发,尽管代码确实在执行。这里有一个简单的例子:
import thread
def go(count):
print 'count is %d.' % count # set break point here
print 'calling from main thread:'
go(13)
print 'calling from bg thread:'
thread.start_new_thread(go, (23,))
raw_input('press enter to quit.')
在这个例子中,当代码在主线程中被调用时,断点会被触发,但当它从后台线程中被调用时,断点就不会被触发。我能做些什么吗?还是说这是PyDev调试器的一个限制呢?
更新
感谢大家提供的解决方法。我提交了一个PyDev功能请求,并且已经完成了。这个功能应该会在1.6.0版本中发布。谢谢,PyDev团队!
4 个回答
问题的根本在于 sys.settrace 这个低级的 Python 函数,它用于进行所有的追踪和调试。正如文档所说,
这个函数是针对每个线程的;如果调试器要支持多个线程,就必须为每个被调试的线程使用 settrace() 注册。
我认为,当你在 PyDev 中设置一个断点时,产生的 settrace
调用总是在主线程上进行(我最近没有查看 PyDev,所以他们可能已经添加了一些解决方法,但我记得之前没有)。
你可以自己尝试的一个解决方法是在主线程中设置断点后,使用 sys.gettrace 来获取 PyDev 的追踪函数,把它保存在一个全局变量中,然后确保在所有相关线程中调用 sys.settrace
,并把那个全局变量作为参数传入——这有点麻烦(尤其是对于在设置断点时已经存在的线程!),但我想不出更简单的替代方法。
问题在于,线程模块里没有一个可以知道线程何时开始的接口。
在你的例子中,你可以自己设置调试器的跟踪功能(就像Alex提到的),下面的代码就是这样做的(如果你不是在远程调试器中,pydevd.connected = True是目前需要的——我会修改pydev,让这个不再需要)。你可能还想添加一个try..except ImportError来处理pydevd的导入(如果你不是在调试器中运行,这个导入会失败)。
def go(count):
import pydevd pydevd.connected = True pydevd.settrace(suspend=False) print 'count is %d.' % count # set break point here
再想想,我觉得pydev可以替代线程模块中的start_new_thread方法,提供自己的函数来设置调试器,然后再调用原来的函数(我刚刚试过,似乎有效,所以如果你使用几个小时后会发布的夜间版本,这个版本将成为未来的1.6.0,它应该可以正常工作,而不需要做任何特别的事情)。