我可以在 `__del__` 方法中使用线程 names/IDs 登录吗?
Can I log with thread names/IDs in `__del__` methods?
在Python标准库的logging
库中,使用%(thread)
或%(threadName)
宏(documented here) calls threading.current_thread
(code),取出一个threading
-内锁。
这个,as per the warnings in the __del__
documentation, causes a problem if you want to log inside __del__
. We've run into a single-threaded deadlocking issue这个造成的
那么,我的问题是:是否有一种从 __del__
方法 内部登录的始终安全的方法?在我们的例子中,记录有关由于其所有者被 GC 导致的连接被关闭的信息会很好,但这可能会在用户打开调试日志记录 [=30] 的情况下(可能不太可能)导致问题=]and 将线程信息添加到它们的调试配置中。我找到了一些关于 more explicit resource-sharing in __del__
的帖子,但是 none 关于 stdlib 日志记录行为的帖子。
threading.current_thread()
的 CPython stdlib version 实际上并没有获取锁。您 运行 遇到的问题是 eventlet 特有的,它会进行大量猴子修补以扰乱线程系统。虽然一种方法可能是停止使用 eventlet,但这可能需要您重写整个应用程序,并且它无法解决您可能最终在日志记录时尝试锁定的任何其他方式 - 例如,如果__str__
方法原来需要一个锁。
在 __del__
中登录或在 __del__
中进行任何复杂工作的最安全方法可能是让 __del__
发送消息告诉其他人代之以进行日志记录的代码。这会在 __del__
和实际记录之间引入延迟,但这种延迟基本上是不可避免的,因为我们必须延迟记录,直到它需要的资源可用。也不会 gua运行tee 记录调用和 __del__
发生在同一个线程上;在非 eventlet 上下文中,调用 current_thread()
来确定哪个线程正在处理 __del__
可能是安全的,但是对于 eventlet,可能没有好的方法。
大多数发送消息的方式都会有类似的线程安全或重发运行cy 问题,但是Python 3.7 添加了 queue.SimpleQueue
class 和 put
方法设计为reent运行t。使用它来管理您的 __del__
-logging 消息可能类似于
import queue
del_log_queue = queue.SimpleQueue()
def stop_del_logging():
del_log_queue.put(None)
...
def __del__(self):
del_log_queue.put((tuple, of, relevant, information))
...
# in some other thread
while True:
info = del_log_queue.get()
if info is None:
break
relevant_logger.log(do_something_with(info))
在非 eventlet 上下文中,让 logging.QueueHandler
and logging.QueueListener
处理 SimpleQueue 可能是安全的,但对于 eventlet,这将不起作用,因为我们需要延迟创建 LogRecord 直到我们'重新退出 __del__
.
在Python标准库的logging
库中,使用%(thread)
或%(threadName)
宏(documented here) calls threading.current_thread
(code),取出一个threading
-内锁。
这个,as per the warnings in the __del__
documentation, causes a problem if you want to log inside __del__
. We've run into a single-threaded deadlocking issue这个造成的
那么,我的问题是:是否有一种从 __del__
方法 内部登录的始终安全的方法?在我们的例子中,记录有关由于其所有者被 GC 导致的连接被关闭的信息会很好,但这可能会在用户打开调试日志记录 [=30] 的情况下(可能不太可能)导致问题=]and 将线程信息添加到它们的调试配置中。我找到了一些关于 more explicit resource-sharing in __del__
的帖子,但是 none 关于 stdlib 日志记录行为的帖子。
threading.current_thread()
的 CPython stdlib version 实际上并没有获取锁。您 运行 遇到的问题是 eventlet 特有的,它会进行大量猴子修补以扰乱线程系统。虽然一种方法可能是停止使用 eventlet,但这可能需要您重写整个应用程序,并且它无法解决您可能最终在日志记录时尝试锁定的任何其他方式 - 例如,如果__str__
方法原来需要一个锁。
在 __del__
中登录或在 __del__
中进行任何复杂工作的最安全方法可能是让 __del__
发送消息告诉其他人代之以进行日志记录的代码。这会在 __del__
和实际记录之间引入延迟,但这种延迟基本上是不可避免的,因为我们必须延迟记录,直到它需要的资源可用。也不会 gua运行tee 记录调用和 __del__
发生在同一个线程上;在非 eventlet 上下文中,调用 current_thread()
来确定哪个线程正在处理 __del__
可能是安全的,但是对于 eventlet,可能没有好的方法。
大多数发送消息的方式都会有类似的线程安全或重发运行cy 问题,但是Python 3.7 添加了 queue.SimpleQueue
class 和 put
方法设计为reent运行t。使用它来管理您的 __del__
-logging 消息可能类似于
import queue
del_log_queue = queue.SimpleQueue()
def stop_del_logging():
del_log_queue.put(None)
...
def __del__(self):
del_log_queue.put((tuple, of, relevant, information))
...
# in some other thread
while True:
info = del_log_queue.get()
if info is None:
break
relevant_logger.log(do_something_with(info))
在非 eventlet 上下文中,让 logging.QueueHandler
and logging.QueueListener
处理 SimpleQueue 可能是安全的,但对于 eventlet,这将不起作用,因为我们需要延迟创建 LogRecord 直到我们'重新退出 __del__
.