You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python线程无法随atexit退出,如何仅修改TeamsHandler实现正常终止?

Fixing the Thread Hang in Your TeamsHandler for Clean Program Termination

Your script is hanging because the way you're using atexit.register(self.queue.put, None) has a subtle flaw: by the time your program tries to exit, the TeamsHandler instance might already be garbage-collected, making self.queue unavailable. That means the None signal never reaches the worker thread, which stays stuck waiting on queue.get() forever.

Here's the fix, modifying only the TeamsHandler class to ensure clean termination:

import logging
from logging import StreamHandler
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()
        # Register our custom cleanup method instead of directly calling queue.put
        atexit.register(self._cleanup)

    def _worker(self):
        while True:
            record = self.queue.get()
            if record is None:
                break
            msg = self.format(record)
            print(msg)
            # Mark the task as done (optional but good practice for queue management)
            self.queue.task_done()

    def emit(self, record):
        self.queue.put(record)

    def _cleanup(self):
        # Send termination signal to the worker thread
        self.queue.put(None)
        # Wait for the worker thread to finish processing remaining tasks and exit
        self.thread.join()

    def close(self):
        # Override close to ensure cleanup runs even when the handler is removed
        self._cleanup()
        super().close()

Let's break down the key changes:

  • Replace the atexit registration: Instead of registering queue.put directly, we use a custom _cleanup method. This method holds a reference to self, so the TeamsHandler instance and its queue won't be garbage-collected before the cleanup runs.
  • Add thread joining: The _cleanup method calls self.thread.join(), which waits for the worker thread to process the termination signal (and any remaining log records in the queue) before exiting. This guarantees all logs are handled before the program shuts down.
  • Add queue.task_done(): While optional, this is good practice for queue management—it lets you use queue.join() later if you need to wait for all pending tasks to finish in other scenarios.
  • Override the close method: Ensures the cleanup logic runs not just on program exit, but also when the handler is explicitly removed from the logger, making the class more robust.

With these changes, your program will exit cleanly: after your log messages are printed, the _cleanup method will send the None signal to the worker thread, which will exit its loop. The main thread waits for the worker to finish, then the program terminates without hanging.

内容的提问来源于stack exchange,提问作者Chapo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 13:32:49