Reputation: 46303
I maintain a threads
list, and I want to auto-remove threads from the list when they are finished.
I found this method:
import threading, time
def f(seconds, info):
print('starting', seconds)
time.sleep(seconds)
print('finished', seconds)
threads.remove(info['thread'])
def newaction(seconds):
info = {}
thread = threading.Thread(target=f, args=(seconds, info))
info['thread'] = thread
thread.start()
threads.append(thread)
threads = []
newaction(1)
newaction(2)
for _ in range(10):
time.sleep(0.3)
print(threads)
It works:
starting 1
starting 2
[<Thread(Thread-1, started 1612)>, <Thread(Thread-2, started 712)>]
[<Thread(Thread-1, started 1612)>, <Thread(Thread-2, started 712)>]
[<Thread(Thread-1, started 1612)>, <Thread(Thread-2, started 712)>]
finished 1
[<Thread(Thread-2, started 712)>]
[<Thread(Thread-2, started 712)>]
[<Thread(Thread-2, started 712)>]
finished 2
[]
[]
[]
[]
But the fact of having to pass a dict info
is a bit a hack. I used it because obviously I can't pass thread
in args
...
thread = threading.Thread(target=f, args=(seconds, thread))
# ^ not created yet!
...when the Thread
object is not created yet!
Is there a more natural way in Python to maintain an auto-cleanable list of threads?
Upvotes: 4
Views: 653
Reputation: 198
Subclassing Thread results in a solution with a natural syntax and a secure place to keep the list of threads. You also don't have to include an instruction to remove the thread at the end of every function you want to run in another thread. Simply use the subclass.
import threading, time
class AutoRemovingThread(threading.Thread):
threads = []
def __init__(self, func, *args, **kwargs):
super().__init__()
self.threads.append(self)
self.func = func
self.args = args
self.kwargs = kwargs
def run(self):
self.func(*self.args, **self.kwargs)
self.threads.remove(self)
def f(seconds):
print('starting', seconds)
time.sleep(seconds)
print('finished', seconds)
def newaction(seconds):
AutoRemovingThread(f, seconds).start()
newaction(1)
newaction(2)
for _ in range(10):
time.sleep(0.3)
print(AutoRemovingThread.threads)
Outputs:
starting 1
starting 2
[<AutoRemovingThread(Thread-1, started 8436)>, <AutoRemovingThread(Thread-2, started 1072)>]
[<AutoRemovingThread(Thread-1, started 8436)>, <AutoRemovingThread(Thread-2, started 1072)>]
[<AutoRemovingThread(Thread-1, started 8436)>, <AutoRemovingThread(Thread-2, started 1072)>]
finished 1
[<AutoRemovingThread(Thread-2, started 1072)>]
[<AutoRemovingThread(Thread-2, started 1072)>]
[<AutoRemovingThread(Thread-2, started 1072)>]
finished 2
[]
[]
[]
[]
python-3.8
Upvotes: 1
Reputation: 13666
You have the current_thread()
function.
import threading, time
def f(seconds):
print('starting', seconds)
time.sleep(seconds)
print('finished', seconds)
threads.remove(threading.current_thread())
def newaction(seconds):
thread = threading.Thread(target=f, args=(seconds,))
thread.start()
threads.append(thread)
threads = []
newaction(1)
newaction(2)
for _ in range(10):
time.sleep(0.3)
print(threads)
Output:
starting 1
starting 2
[<Thread(Thread-1, started 4588)>, <Thread(Thread-2, started 4388)>]
[<Thread(Thread-1, started 4588)>, <Thread(Thread-2, started 4388)>]
[<Thread(Thread-1, started 4588)>, <Thread(Thread-2, started 4388)>]
finished 1
[<Thread(Thread-2, started 4388)>]
[<Thread(Thread-2, started 4388)>]
[<Thread(Thread-2, started 4388)>]
finished 2
[]
[]
[]
[]
Upvotes: 3
Reputation: 476
import threading
def get_status_of_threads():
current_threads = threading.enumerate()
thread_data = []
for item in current_threads:
try:
print(str(item.target))
except AttributeError:
print("item", str(item))
thread_data.append({"thread_name": item.getName(), "status": int(item.is_alive()), "id": item.ident})
return thread_data
The above code is tested in Python2.7, you can use this in a separate thread if you want to continuously monitor the threads, or you can expose this as an API, so you can check whenever you want. That will also help in less wastage of resources for the same.
For API, you can use json2html.convert({"thread_data":thread_data})
function to display it in a more aesthetic way in a tabular form.
Upvotes: 0