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



当我设置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

首先安装prctl模块。(在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。

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

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

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

在Python 2上,如果系统中安装了prctl,我会使用以下monkey补丁将线程的名称传播到系统:

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%安全的,但它对我有效。

我发现了一个在运行时显示python线程的工具--py spy,这让我很困惑。

安装:pip3安装-ihttps://pypi.doubanio.com/simple/py间谍

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

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

另一种解决方案(实际上是脏的,因为它设置的是进程名称,而不是线程名称)是使用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()

https://pypi.org/project/namedthreads/提供了一种用Python Thread.name修补threading.Thread.start以调用pthread_setname_np的方法。

它与Python 2.7&3.4+(我用3.10测试过)

要激活它,

import namedthreads
namedthreads.patch()

请注意,Python中的线程名称是无限的,但pthreads的限制是15个字符,因此Python名称将被修剪。

我试图按照此处的答案安装python-prctlpyprctl。然而,由于需要一个我们没有的gcc,它们都无法安装。

经过网络上的一些挖掘,这个蟒蛇问题15500给出了一个很好的解决方案[https://bugs.python.org/issue15500]。以下是我基于它得到的:

导入ctypes、os、线程def set_thread_name_np(名称):_lib_path="/lib/libpthread-2.42.so"如果不是os.path.isfile(_lib_path):return无尝试:libpthread=ctypes。CDLL(_lib_path)除了:return无如果hasattr(libpthread,"pthread_setname_np"):pthread_setname_np=libpthread.pthread_setnamepthread_setname_np.argtypes=[cytpes.c_void_p,ctypes.cchar_p]pthread_setname_np.restype=ctypes.c_int如果是instance(the_name,str):the_name=the_name.encode('scii','replace')如果类型(the_name)不是字节:return无the_thread=threading.current_thread()ident=getattr(线程,"ident",无)如果ident不是None:pthread_setname_np(ident,the_name[:15])return Truereturn无

相关内容

  • 没有找到相关文章

最新更新