Python线程未使用atexit退出
问题描述
这是我的脚本。当我在外壳中运行它时,它只是无限期地挂起,而我希望它干净地终止。
import logging
from logging import StreamHandler
import pymsteams
import queue
import threading
import atexit
class TeamsHandler(StreamHandler):
def __init__(self, channel_url):
super().__init__()
self.channel_url = channel_url
self.queue = queue.Queue()
self.thread = threading.Thread(target=self._worker)
self.thread.start()
atexit.register(self.queue.put, None)
def _worker(self):
while True:
record = self.queue.get()
if record is None:
break
msg = self.format(record)
print(msg)
def emit(self, record):
# enqueue the record to log and return control to the caller
self.queue.put(record)
if __name__ == "__main__":
my_logger = logging.getLogger('TestLogging')
my_logger.setLevel(logging.DEBUG)
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.DEBUG)
my_logger.addHandler(console_handler)
CHANNEL_ID = "not_used_anyway"
teamshandler = TeamsHandler(CHANNEL_ID)
teamshandler.setFormatter(logging.Formatter('%(levelname)s %(message)s'))
teamshandler.setLevel(logging.DEBUG)
my_logger.addHandler(teamshandler)
for i in range(1, 2):
my_logger.error(f"this is an error [{i}]")
my_logger.info(f"this is an info [{i}]")
应由atexit
(第28行)发送的None
记录从未到达,因此线程始终保持打开状态。
如何通过仅修改TeamsHandler
确保程序干净退出?
解决方案
正如avysk指出的,问题可能是atexit
处理程序启动太晚,在等待非后台进程线程已经(应该)完成之后,这会导致死锁。
如果我是你,我只会在if __name__ == '__main__'
块的末尾添加一个类似TeamsHandler.finish()
的调用,并按如下方式修改TeamsHandler
(未测试):
_queues = []
class TeamsHandler(StreamHandler):
def __init__(self, channel_url):
super().__init__()
self.channel_url = channel_url
self.queue = queue.Queue()
self.thread = threading.Thread(target=self._worker)
self.thread.start()
_queues.append(self.queue)
def _worker(self):
while True:
record = self.queue.get()
if record is None:
break
msg = self.format(record)
print(msg)
def emit(self, record):
# enqueue the record to log and return control to the caller
self.queue.put(record)
@staticmethod
def finish(self):
for q in _queues:
q.put(None)
del _queues[:]
相关文章