38

When I set the name for a Python thread, it doesn't show up on htop or ps. The ps output only shows python as the thread name. Is there any way to set a thread name so that it shows up on system reports like them?

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} output

  PID  SPID TTY          TIME CMD
31420 31420 pts/30   00:00:00 python
31420 31421 pts/30   00:00:00 python
Błażej Michalik
  • 4,474
  • 40
  • 55
chamilad
  • 1,619
  • 3
  • 23
  • 40

7 Answers7

33

First install the prctl module. (On debian/ubuntu just type 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()

This prints

$ 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

Note: python3 users may wish to use pyprctl.

gerardw
  • 5,822
  • 46
  • 39
Nick Craig-Wood
  • 52,955
  • 12
  • 126
  • 132
  • 1
    Thanks @NickCraig-Wood! Why doesn't Python straightaway pass the given name in to prctl when creating threads from Thread class? – chamilad Dec 21 '15 at 04:45
  • Don't install prctl with `pip` or you get `AttributeError: 'module' object has no attribute 'get_name'`. – BurnsBA Feb 01 '16 at 21:11
  • 4
    @BurnsBA you need `pip install python-prctl` to get this functionality. The pip module named `prctl` does not have the `set_name` function. – John Slade Mar 04 '16 at 11:01
  • 3
    on my linux mint 18.1 (ubuntu) install, I had to use ```ps -eT``` to see the thread name. – pbnelson Jan 16 '17 at 22:12
  • 3
    debian currently lacks a python3-prctl so I had to `pip3 install python-prct` as JohnTESlade suggested. also it needs `apt install libcap-dev` before. – melissa_boiko May 29 '18 at 17:41
  • …but it didn't change the process name as seen on `top` or `ps`. then I tried `setproctitle` from pip and that one worked. – melissa_boiko May 29 '18 at 17:47
  • 2
    So what is the relationship to python's threading API's `name` property? what good is name="Sleeper01" here? – matanster May 19 '20 at 19:15
  • 1
    In my short experience, this approach may mangle thread names if not used right across different threads, as each thread essentially overwrites the name in a global way. – matanster Jun 03 '20 at 19:21
  • When using top, launch it in 'thread mode' to see the individual thread-names: `top -H` – chjortlund Jan 07 '21 at 09:23
12

Prctl module is nice and provide many features, but depends libcap-dev package. Libcap2 is most likely installed because it is a dependency of many packages (systemd for example). So if you only need set thread name, use libcap2 over ctypes.

See improved Grief answer below.

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
Oleg Golovanov
  • 121
  • 1
  • 4
  • 2
    This worked for me, be sure to use `ps -T` when checking if it worked. Also, for Ubuntu at least, the character limit for thread names is 15 so keep it below that if you're using the names in a grep kind of case. – Eric Blum Sep 10 '18 at 23:40
8

On Python 2, I use the following monkey patch to propagate the Thread's name to the system if prctl is installed in the system:

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

After the execution of this code, you can set thread's name as usual:

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

That means, that if you already set names for threads, you don't need to change anything. I cannot guarantee, that this is 100% safe, but it works for me.

John Vandenberg
  • 474
  • 6
  • 16
Grief
  • 1,839
  • 1
  • 21
  • 40
1

I was confused after I found a tool--py-spy to show python thread while running.

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

usage: py-spy dump --pid process-number

for example, py-spy dump --pid 1234 can show all the thread stacks,name,id of python process 1234

ryanlee
  • 341
  • 3
  • 9
0

An alternative solution (actually a dirty one, since it sets the process name, not the thread name) is to use the setproctitle module from pypi.

You can install it with pip install setproctitle and use it as follow:

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()
Lan Quil
  • 13
  • 8
0

https://pypi.org/project/namedthreads/ provides a way to patch threading.Thread.start to call pthread_setname_np with the Python Thread.name.

It is compatible with Python 2.7 & 3.4+ (I've tested it with 3.10)

To activate it,

import namedthreads
namedthreads.patch()

Note that thread names in Python are unlimited, but pthreads has a limit of 15 char, so the Python name will be trimmed.

John Vandenberg
  • 474
  • 6
  • 16
0

I attempted to follow answers here to install python-prctl or pyprctl. However none of them could be installed because the need for a gcc that we don't have.

After some digging on the net, this python issue 15500 gave a nice solution [https://bugs.python.org/issue15500]. Here is what I've got based on it:

import ctypes, os, threading
def set_thread_name_np(the_name):
    the_lib_path = "/lib/libpthread-2.42.so"
    if not os.path.isfile(the_lib_path):
        return None
    try:
        libpthread = ctypes.CDLL(the_lib_path)
    except:
        return None
    if hasattr(libpthread, "pthread_setname_np"):
        pthread_setname_np = libpthread.pthread_setname_np
        pthread_setname_np.argtypes = [ctypes.c_void_p,
                                       ctypes.c_char_p]
        pthread_setname_np.restype = ctypes.c_int
        if isinstance(the_name, str):
            the_name = the_name.encode('ascii', 'replace')
        if type(the_name) is not bytes:
            return None
        the_thread = threading.current_thread()
        ident = getattr(the_thread, "ident", None)
        if ident is not None:
            pthread_setname_np(ident, the_name[:15])
            return True
    return None
minghua
  • 5,981
  • 6
  • 45
  • 71