Reputation: 7302
This ie example program:
import logging
import threading
import random
import time
import sys
def Thread1(a, b):
logging.info('INIT')
while True:
r = random.randint(a, b)
logging.debug(f'sleep for {r} seconds')
logging.debug(f'5 / {r} = { 5 / r}') # possible: ZeroDivisionError: division by zero
time.sleep(r)
continue
logging.info('Exiting')
def Thread2(a, b):
logging.info('INIT')
while True:
r = random.randint(a, b)
logging.debug(f'5 / {r} = { 5 / r}') # possible: ZeroDivisionError: division by zero
logging.debug(f'sleep for {r} seconds')
time.sleep(r)
continue
logging.info('Exiting')
#
# my_excepthook
#
def my_excepthook(args):
#print(f'In excepthook {args=} --- {type(args)}')
exc_type, exc_value, exc_traceback = sys.exc_info()
print( 'Handling %s exception with message "%s" in %s' % \
(exc_type.__name__, exc_value, threading.current_thread().name))
if threading.current_thread().name == 'Thread_1':
t1 = threading.Thread(name='Thread_1', target=Thread1, args=(0, 4), daemon=False)
t1.start()
if threading.current_thread().name == 'Thread_2':
t2 = threading.Thread(name='Thread_2', target=Thread2, args=(0, 4), daemon=False)
t2.start()
threading.excepthook = my_excepthook
if __name__ == "__main__":
format='%(asctime)s - %(threadName)10s - %(lineno)4d - %(message)s'
logging.basicConfig(level=logging.DEBUG, format=format)
#
# When there is exception, thread will stop working
#
t1 = threading.Thread(name='Thread_1', target=Thread1, args=(0, 4), daemon=False)
t1.start()
#
# When there is exception, thread will stop working
#
t2 = threading.Thread(name='Thread_2', target=Thread2, args=(0, 4), daemon=False)
t2.start()
#
# How to restart thread manually
#
# logging.debug('Before Main loop')
# while True:
# time.sleep(5) # how often to check
# if t1.is_alive() == False:
# logging.critical('Restarting Thread_1')
# t1 = threading.Thread(name='Thread_1', target=Thread1, args=(0, 10), daemon=True)
# t1.start()
# if t2.is_alive() == False:
# logging.critical('Restarting Thread_2')
# t2 = threading.Thread(name='Thread_2', target=Thread1, args=(0, 10), daemon=True)
# t2.start()
logging.info('MAIN END')
My question if what is Python way to restart thread ?
So far I have found 2 alternatives ?
First: is to have infinite loop ate end of main program, where check is_alive() is called on each thread and restart it if necessary.
Second: is to use threading.excepthook with custom function. Because in both alternatives I need to check is_alive()on each thread, they are more or less same approach. Only benefit of threading.excepthook is that there is no delay in restarting thread.
Am I missing something, is there a better way ?
Any feedback appreciated.
Upvotes: 1
Views: 851
Reputation: 3846
You can try to restructure your code and use ThreadPoolExecutor
and pool.submit
, if any error happens inside pool's thread, the error will be ignored. On the other hand, my personal choice is to wrap all code in other threads in try ... except Exception
block.
import logging
import random
import time
from concurrent.futures import ThreadPoolExecutor
from functools import partial
def some_func(_, a, b):
r = random.randint(a, b)
logging.debug(f'sleep for {r} seconds')
logging.debug(f'5 / {r} = {5 / r}') # possible: ZeroDivisionError: division by zero
time.sleep(r)
if __name__ == '__main__':
logging.basicConfig(format="%(threadName)s | %(asctime)s | %(msg)s", level=logging.DEBUG)
# better to generate tasks in Main thread, than make infinite loop in child thread
tasks = [_ for _ in range(10000)]
with ThreadPoolExecutor(4) as pool:
# send tasks to other threads
for t in tasks:
pool.submit(partial(some_func, a=0, b=1), t)
Upvotes: 1