我经常被问到如何杀死一个后台线程,这个问题的答案让很多人不开心: 线程是杀不死的。在本文中,我将向您展示 Python 中用于终止线程的两个选项。
如果我们是一个好奇宝宝的话,可能会遇到这样一个问题,就是:如何杀死一个 Python 的后台线程呢?我们可能尝试解决这个问题,却发现线程是杀不死的。而本文中将展示,在 Python 中用于终止线程的两个方式。
1. 线程无法结束
A Threaded Example
- import random
- import threading
- import time
- def bg_thread():
- for i in range(1, 30):
- print(f'{i} of 30 iterations...')
- time.sleep(random.random()) # do some work...
- print(f'{i} iterations completed before exiting.')
- th = threading.Thread(target=bg_thread)
- th.start()
- th.join()
- $ python thread.py
- 1 of 30 iterations...
- 2 of 30 iterations...
- 3 of 30 iterations...
- 4 of 30 iterations...
- 5 of 30 iterations...
- 6 of 30 iterations...
- 7 of 30 iterations...
- ^CTraceback (most recent call last):
- File "thread.py", line 14, in <module>
- th.join()
- File "/Users/mgrinberg/.pyenv/versions/3.8.6/lib/python3.8/threading.py", line 1011, in join
- self._wait_for_tstate_lock()
- File "/Users/mgrinberg/.pyenv/versions/3.8.6/lib/python3.8/threading.py", line 1027, in _wait_for_tstate_lock
- elif lock.acquire(block, timeout):
- KeyboardInterrupt
- 8 of 30 iterations...
- 9 of 30 iterations...
- 10 of 30 iterations...
- 11 of 30 iterations...
- 12 of 30 iterations...
- 13 of 30 iterations...
- ^CException ignored in: <module 'threading' from '/Users/mgrinberg/.pyenv/versions/3.8.6/lib/python3.8/threading.py'>
- Traceback (most recent call last):
- File "/Users/mgrinberg/.pyenv/versions/3.8.6/lib/python3.8/threading.py", line 1388, in _shutdown
- lock.acquire()
- KeyboardInterrupt:
2. 使用守护进程
Daemon Threads
- import random
- import threading
- import time
- def bg_thread():
- for i in range(1, 30):
- print(f'{i} of 30 iterations...')
- time.sleep(random.random()) # do some work...
- print(f'{i} iterations completed before exiting.')
- th = threading.Thread(target=bg_thread)
- th.daemon = True
- th.start()
- th.join()
- ~ $ python x.py
- 1 of 30 iterations...
- 2 of 30 iterations...
- 3 of 30 iterations...
- 4 of 30 iterations...
- 5 of 30 iterations...
- 6 of 30 iterations...
- ^CTraceback (most recent call last):
- File "thread.py", line 15, in <module>
- th.join()
- File "/Users/mgrinberg/.pyenv/versions/3.8.6/lib/python3.8/threading.py", line 1011, in join
- self._wait_for_tstate_lock()
- File "/Users/mgrinberg/.pyenv/versions/3.8.6/lib/python3.8/threading.py", line 1027, in _wait_for_tstate_lock
- elif lock.acquire(block, timeout):
- KeyboardInterrupt
3. 使用事件对象
Python Events
Event 类是由 Python 标准库的线程模块提供,你可以通过实例化类来创建一个事件对象,就像下面这个样子:
- exit_event = threading.Event()
- import random
- import signal
- import threading
- import time
- exit_event = threading.Event()
- def bg_thread():
- for i in range(1, 30):
- print(f'{i} of 30 iterations...')
- time.sleep(random.random()) # do some work...
- if exit_event.is_set():
- break
- print(f'{i} iterations completed before exiting.')
- def signal_handler(signum, frame):
- exit_event.set()
- signal.signal(signal.SIGINT, signal_handler)
- th = threading.Thread(target=bg_thread)
- th.start()
- th.join()
- $ python thread.py
- 1 of 30 iterations...
- 2 of 30 iterations...
- 3 of 30 iterations...
- 4 of 30 iterations...
- 5 of 30 iterations...
- 6 of 30 iterations...
- 7 of 30 iterations...
- ^C7 iterations completed before exiting.
- for i in range(1, 30):
- print(f'{i} of 30 iterations...')
- time.sleep(random.random())
- if exit_event.is_set():
- break
- for i in range(1, 30):
- print(f'{i} of 30 iterations...')
- if exit_event.wait(timeout=random.random()):
- break
4. 总结陈述说明
Conclusion