Python 线程名称未显示在 ps 或 htop 上

Posted

技术标签:

【中文标题】Python 线程名称未显示在 ps 或 htop 上【英文标题】:Python thread name doesn't show up on ps or htop 【发布时间】:2016-03-25 11:34:46 【问题描述】:

当我为 Python 线程设置名称时,它不会显示在 htop 或 ps 上。 ps 输出仅显示python 作为线程名称。有什么方法可以设置线程名称,以便它显示在类似它们的系统报告中?

from threading import Thread
import time


def sleeper():
    while True:
        time.sleep(10)
        print "sleeping"

t = Thread(target=sleeper, name="Sleeper01")
t.start()
t.join()

ps -T -p PID 输出

  PID  SPID TTY          TIME CMD
31420 31420 pts/30   00:00:00 python
31420 31421 pts/30   00:00:00 python

【问题讨论】:

我认为这是duplicate @NickCraig-Wood:不是真的,这个问题不是关于 C,而是关于 Python。 @NickCraig-Wood 谢谢尼克!我现在正在阅读 pthreads。是的,这有帮助,但它仍然不能回答我关于 Python 的问题(或者我错过了什么?) 如果你启动一个新进程而不是一个线程会发生什么? @VincentSavard 我的错,你是对的! 【参考方案1】:

首先安装prctl module。 (在 debian/ubuntu 上只需输入 sudo apt-get install python-prctl

from threading import Thread
import time
import prctl

def sleeper():
    prctl.set_name("sleeping tiger")
    while True:
        time.sleep(10)
        print "sleeping"

t = Thread(target=sleeper, name="Sleeper01")
t.start()
t.join()

打印出来

$ ps -T
  PID  SPID TTY          TIME CMD
22684 22684 pts/29   00:00:00 bash
23302 23302 pts/29   00:00:00 python
23302 23303 pts/29   00:00:00 sleeping tiger
23304 23304 pts/29   00:00:00 ps

注意:python3 用户不妨使用pyprctl。

【讨论】:

感谢@NickCraig-Wood!为什么 Python 在从 Thread 类创建线程时不直接将给定名称传递给 prctl? @BurnsBA 您需要pip install python-prctl 才能获得此功能。名为prctl 的pip 模块没有set_name 功能。 在我的 linux mint 18.1 (ubuntu) 安装中,我必须使用 ps -eT 来查看线程名称。 debian 目前缺少 python3-prctl,所以我不得不按照 JohnTESlade 的建议pip3 install python-prct。它还需要apt install libcap-dev 那么与python的线程API的name属性有什么关系呢? name="Sleeper01" 有什么用?【参考方案2】:

Prctl 模块很好,提供了很多功能,但依赖于 libcap-dev 包。 Libcap2 很可能已安装,因为它是许多软件包的依赖项(例如 systemd)。因此,如果您只需要设置线程名称,请使用 libcap2 而不是 ctypes。

请参阅下面改进的悲伤答案。

LIB = 'libcap.so.2'
try:
    libcap = ctypes.CDLL(LIB)
except OSError:
    print(
        'Library  not found. Unable to set thread name.'.format(LIB)
    )
else:
    def _name_hack(self):
        # PR_SET_NAME = 15
        libcap.prctl(15, self.name.encode())
        threading.Thread._bootstrap_original(self)

    threading.Thread._bootstrap_original = threading.Thread._bootstrap
    threading.Thread._bootstrap = _name_hack

【讨论】:

这对我有用,在检查它是否有效时一定要使用ps -T。此外,至少对于 Ubuntu,线程名称的字符数限制为 15,因此如果您在 grep 类型的情况下使用名称,请将其保持在该值以下。【参考方案3】:

如果系统中安装了prctl,我使用以下猴子补丁将python线程的名称传播到系统:

try:
    import prctl
    def set_thread_name(name): prctl.set_name(name)

    def _thread_name_hack(self):
        set_thread_name(self.name)
        threading.Thread.__bootstrap_original__(self)

    threading.Thread.__bootstrap_original__ = threading.Thread._Thread__bootstrap
    threading.Thread._Thread__bootstrap = _thread_name_hack
except ImportError:
    log('WARN: prctl module is not installed. You will not be able to see thread names')
    def set_thread_name(name): pass

这段代码执行后,你可以像往常一样设置线程的名字:

threading.Thread(target=some_target, name='Change monitor', ...)

这意味着,如果您已经为线程设置了名称,则无需更改任何内容。我不能保证这是 100% 安全的,但它对我有用。

【讨论】:

【参考方案4】:

另一种解决方案(实际上是一个肮脏的解决方案,因为它设置进程名称,而不是线程名称)是使用 pypi 中的 setproctitle 模块。

您可以使用pip install setproctitle 安装它并按如下方式使用它:

import setproctitle
import threading
import time

def a_loop():
    setproctitle.setproctitle(threading.currentThread().name)
    # you can otherwise explicitly declare the name:
    # setproctitle.setproctitle("A loop")
    while True:
        print("Looping")
        time.sleep(99)

t = threading.Thread(target=a_loop, name="ExampleLoopThread")
t.start()

【讨论】:

虽然仍然有用,但这个答案并不正确。它设置进程标题,而不是线程标题 @Wolph:感谢您的评论,我已将其插入答案中。【参考方案5】:

在找到一个工具--py-spy 可以在运行时显示 python 线程后,我感到很困惑。

安装:pip3 install -i https://pypi.doubanio.com/simple/py-spy

用法:py-spy dump --pid 进程号

例如py-spy dump --pid 1234 可以显示python进程1234的所有线程堆栈、名称、id

【讨论】:

以上是关于Python 线程名称未显示在 ps 或 htop 上的主要内容,如果未能解决你的问题,请参考以下文章

htop 线程也有pid吗?

在 htop 中更改或隐藏进程名称

在 htop 中搜索特定的进程名称

ps显示线程名称

为啥“htop”会显示我的应用程序正在使用的几十个 PID,而“ps”只显示一个?

htop top ps dstat 命令的使用