Reputation: 1659
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
Upvotes: 40
Views: 18244
Reputation: 6581
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
Upvotes: 1
Reputation: 535
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.
Upvotes: 1
Reputation: 2040
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.
Upvotes: 8
Reputation: 381
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
Upvotes: 1
Reputation: 54081
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.
Upvotes: 33
Reputation: 11
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()
Upvotes: -1
Reputation: 131
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
Upvotes: 12