CPython stdlib версия из threading.current_thread()
фактически не принимает блокировку. Проблема, с которой вы столкнулись, имеет отношение к eventlet, который делает кучу патчей, чтобы связываться с системой потоков. Хотя одним из подходов может быть прекращение использования eventlet, для этого, вероятно, потребуется переписать все приложение целиком, и это не исправит ни один из других способов, с помощью которых вы можете попытаться получить блокировку во время регистрации - например, если __str__
метод оказывается нужным для блокировки.
Самым близким к безопасному способу входа в систему __del__
или выполнения какой-либо сложной работы в __del__
, вероятно, является вместо этого __del__
отправить сообщение, сообщающее некоторому другому коду для ведения журнала вместо этого. Это привело бы к задержке между __del__
и фактическим ведением журнала, но такая задержка, по сути, неизбежна, поскольку мы должны задерживать ведение журнала до тех пор, пока необходимые ему ресурсы не будут доступны. Это также не гарантирует, что вызов регистрации и __del__
происходят в одном потоке; в контексте не-eventlet, вероятно, безопасно вызывать current_thread()
, чтобы выяснить, какой поток обрабатывает __del__
, но с помощью eventlet, вероятно, нет хорошего способа.
У большинства способов отправки сообщения были бы аналогичные проблемы безопасности потока или повторного входа, но Python 3.7 добавляет класс queue.SimpleQueue
с методом put
, предназначенным для повторного входа. Использование его для управления __del__
сообщениями журнала может выглядеть примерно так:
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
и logging.QueueListener
для обработки SimpleQueue, но с eventlet это не сработает, потому что нам нужно отложить создание LogRecord, пока у нас не выйдет __del__
.