python:是否可以将控制台附加到正在运行的进程中

时间:2010-11-12 11:04:01

标签: python

我只想查看进程的状态,是否可以将控制台附加到进程中,因此我可以调用进程内的函数并查看一些全局变量。

这个过程运行得更好而不会受到影响(当然性能会有所下降)

7 个答案:

答案 0 :(得分:55)

这会中断你的进程(除非你在一个线程中启动它),但你可以使用code模块启动一个Python控制台:

import code
code.interact()

这将阻止,直到用户通过执行exit()退出交互式控制台。

code模块至少可以在Python v2.6中使用,可能还有其他模块。

我倾向于将这种方法与我的Linux工作的信号结合使用(对于Windows,见下文)。我把它放在Python脚本的顶部:

import code
import signal
signal.signal(signal.SIGUSR2, lambda sig, frame: code.interact())

然后从kill -SIGUSR2 <PID>的shell中触发它,其中<PID>是进程ID。然后,该过程将停止正在执行的操作并显示控制台:

Python 2.6.2 (r262:71600, Oct  9 2009, 17:53:52)
[GCC 3.4.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>>

通常从那里我将加载远程调试器的服务器端组件,如优秀的WinPDB

Windows不是POSIX兼容的操作系统,因此不提供与Linux相同的信号。但是,Python v2.2 and above expose a Windows-specific signal SIGBREAK(按CTRL + Pause/Break触发)。这干扰正常CTRL + CSIGINT)操作,因此是一个方便的替代方案。

因此,以上的便携式但略显丑陋的版本是:

import code
import signal
signal.signal(
        vars(signal).get("SIGBREAK") or vars(signal).get("SIGUSR2"),
        lambda sig, frame: code.interact()
        )

这种方法的优点:

  • 没有外部模块(所有标准Python的东西)
  • 在触发(2x导入)
  • 之前,几乎不消耗任何资源

这是我在生产环境中使用的代码,它将加载WinPDB的服务器端(如果可用)并回退到打开Python控制台。

# Break into a Python console upon SIGUSR1 (Linux) or SIGBREAK (Windows:
# CTRL+Pause/Break).  To be included in all production code, just in case.
def debug_signal_handler(signal, frame):
    del signal
    del frame

    try:
        import rpdb2
        print
        print
        print "Starting embedded RPDB2 debugger. Password is 'foobar'"
        print
        print
        rpdb2.start_embedded_debugger("foobar", True, True)
        rpdb2.setbreak(depth=1)
        return
    except StandardError:
        pass

    try:
        import code
        code.interact()
    except StandardError as ex:
        print "%r, returning to normal program flow" % ex

import signal
try:
    signal.signal(
            vars(signal).get("SIGBREAK") or vars(signal).get("SIGUSR1"),
            debug_signal_handler
            )
except ValueError:
    # Typically: ValueError: signal only works in main thread
    pass

答案 1 :(得分:40)

如果您可以访问该程序的源代码,则可以相对轻松地添加此功能。

请参阅Recipe 576515Debugging a running python process by interrupting and providing an interactive prompt (Python)

引用:

  

这提供了允许任何python的代码   使用它的程序   在当前点中断,并且   通过普通的python进行交流   互动控制台。这允许   本地人,全局和相关的程序   国家待调查,以及   调用任意函数和   类。

     

要使用,进程应导入   模块,并在任何时候调用listen()   在启动期间。打断这个   进程,脚本可以运行   直接给出过程的ID   调试的过程作为参数。


rconsole提供了大致相同概念的另一种实现方式。来自文档:

  

rconsole是一个远程Python控制台   自动完成,可以   用来检查和修改   正在运行的脚本的命名空间。

     

要在脚本中调用,请执行以下操作:

from rfoo.utils import rconsole
rconsole.spawn_server()
  

要从shell附加,请执行以下操作:

$ rconsole
  

安全说明:rconsole侦听器   以spawn_server()开头   接受任何本地连接,并可能   因此在共享中使用是不安全的   托管或类似的环境!

答案 2 :(得分:21)

使用pyrasite-shell。我无法相信它运作良好,但确实如此。 “给它一个pid,获得一个shell ”。

$ sudo pip install pyrasite
$ echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope # If YAMA activated, see below.
$ pyrasite-shell 16262
Pyrasite Shell 2.0
Connected to 'python my_script.py'
Python 2.7.6 (default, Jun 22 2015, 17:58:13) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.

>>> globals()
>>> print(db_session)
>>> run_some_local_function()
>>> some_existing_local_variable = 'new value'

这将启动python shell,可以访问运行python进程的globals()和locals()变量,以及其他很棒的东西。

仅在Ubuntu上亲自测试过,但似乎也适合OSX。

改编自this answer

注意:关闭ptrace_scope属性的行仅对于使用CONFIG_SECURITY_YAMA构建的内核/系统是必需的。在敏感环境中小心使用ptrace_scope,因为它可能会引入某些安全漏洞。有关详细信息,请参阅here

答案 3 :(得分:6)

为什么不简单地使用pdb模块?它允许您停止脚本,检查元素值,并逐行执行代码。由于它是基于Python解释器构建的,因此它还提供了经典解释器提供的功能。要使用它,只需将这两行放在您希望停止并检查它的代码中:

import pdb
pdb.set_trace()

答案 4 :(得分:4)

此处描述了另一种可能,即不向python脚本添加内容:

https://wiki.python.org/moin/DebuggingWithGdb

不幸的是,这个解决方案还需要一些预先考虑,至少在某种程度上你需要使用带有调试符号的python版本。

答案 5 :(得分:1)

使用PyCharm,我在Ubuntu中无法连接到进程。解决此问题的方法是禁用YAMA。有关详细信息,请参阅askubuntu

echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope

答案 6 :(得分:1)

pdb_attach 非常适合我们将 Python 调试器附加到长时间运行的进程。

作者描述如下: 这个包是为了应对调试长时间运行的进程的挫败感而制作的。将 pdb 附加到正在运行的 python 程序并查看发生了什么不是很好吗?嗯,这正是 pdb-attach 所做的。

在您的主模块中进行如下设置:

pdb_attach.listen()

当程序运行时,通过从命令行调用 pdb_attach 将程序的 PID 和传递给 $ python -m pdb_attach <PID> 50000 (Pdb) # Interact with pdb as you normally would 的端口附加到它:


def top_3_words(text):
    
    new_list = []
    
    new_text = text.lower().split()
    
    for word in new_text:
        for char in word:
            if char.isalpha():
                pass   
            else:
                new_text.remove(char)
             


    Count = Counter(new_text)
    most_occur = Count.most_common(3)
    
    for l in most_occur:
        new_list.append(l[0])
    
    return new_list