Почему __del__ не вызывается для глобального объекта, когда активен другой поток? - PullRequest
0 голосов
/ 28 января 2019

Я работаю над проектом, конструкция которого похожа на приведенную ниже.Я надеюсь иметь объект, который открывает поток при создании и автоматически закрывает его, когда объект уничтожается.Это работает, как и ожидалось, когда объект создается внутри функции, но когда объект создается в глобальной области, __del__ не вызывается, что приводит к зависанию программы.

import threading

def thread(event):
    event.wait()
    print("Terminating thread")

class ThreadManager:
    def __init__(self):
        self.event = threading.Event()
        self.thread = threading.Thread(target=thread, args=(self.event,))
        self.thread.start()

    def __del__(self):
        self.event.set()
        print("Event set")
        self.thread.join()

if __name__ == '__main__':
    print("Creating thread")
    manager = ThreadManager()
    #del manager

Если я явно неудалить объект manager, программа зависает.Я предполагаю, что интерпретатор ожидает удаления глобальных объектов до тех пор, пока не будут завершены все потоки, не являющиеся демонами, что вызовет ситуацию взаимоблокировки.

У меня вопрос, может ли кто-нибудь подтвердить это и предложить обходной путь (я прочитал на этой странице, поэтому я не ищу решения с использованием функции close() или чего-то подобного, мне просто любопытно услышать идеи альтернативы, которая бы выполняла автоматическую очистку), или же опровергнуть ееи скажи мне, что я делаю не так?

1 Ответ

0 голосов
/ 28 января 2019

В отличие от языков, таких как C ++, Python не уничтожает объекты, как только они выходят из области видимости, и поэтому __del__ ненадежен.Вы можете узнать больше об этом здесь: https://stackoverflow.com/a/35489349/5971137

Что касается решения, я думаю, что это идеальный случай для контекстного менеджера (with):

>>> import threading
>>>
>>> def thread(event):
...     event.wait()
...     print("Terminating thread")
...
>>> class ThreadManager:
...     def __init__(self):
...             print("__init__ executed")
...             self.event = threading.Event()
...             self.thread = threading.Thread(target=thread, args=(self.event,))
...             self.thread.start()
...     def __enter__(self):
...             print("__enter__ executed")
...             return self
...     def __exit__(self, *args):
...             print("__exit__ executed")
...             self.event.set()
...             print("Event set")
...             self.thread.join()
...
>>> with ThreadManager() as thread_manager:
...     print(f"Within context manager, using {thread_manager}")
...
__init__ executed
__enter__ executed
Within context manager, using <__main__.ThreadManager object at 0x1049666d8>
__exit__ executed
Event set
Terminating thread

The *Операторы 1009 * показывают, что порядок выполнения работает так, как вы хотите, где __exit__ теперь ваш надежный метод очистки.

...