Python Threading. Класс не будет удален, если ему принадлежит запущенный поток - PullRequest
0 голосов
/ 05 октября 2019

Я пытаюсь создать пакет python для вызова неблокирующих команд. Я придумал простой класс «Исполнитель», который будет иметь поток и очередь с командами для выполнения одной за другой. Хотя кажется, что исключение команд работает, программа никогда не завершает свою работу, поскольку класс-исполнитель никогда не удаляется сборщиком мусора после того, как объект выходит из области видимости.

import threading
import queue
import time
import weakref

class Commands:
    """Class for all Commands"""
    Command: str = ""
    IsDone: bool = False
    WasSuccessfull: bool = False
    Value: object = None

    def __init__(self, InputCommand):
        self.Command = InputCommand

    def GetValue(self) -> object:
        while not self.IsDone:
            time.sleep(0.01)

        return self.Value

    def WaitForFinished(self):
        while not self.IsDone:
            time.sleep(0.01)



class Executer:       
    CommandQueue: queue.Queue = queue.Queue()
    Worker: threading.Thread = None

    def __init__(self):
        self.Worker = threading.Thread(target=weakref.proxy(Executer.__WorkerThread__), args=(weakref.proxy(self) ,))
        self.Worker.start()


    def __del__(self):
        print("Exiting")
        self.AddCommand("__STOP__")
        self.Worker.join()


    def AddCommand(self, CommandText) -> Commands:
        Command = Commands(CommandText)
        self.CommandQueue.put(Command)
        return Command

    def __WorkerThread__ (self):
        while True:
            if self.CommandQueue.empty():
                time.sleep(0.01)
            else:
                Command = self.CommandQueue.get()
                print(Command.Command)
                # Emulate some work
                time.sleep(0.5)
                Command.IsDone = True
                Command.WasSuccessfull = True
                if(Command.Command == "__STOP__"):
                    break


if __name__ == "__main__":
    exe = Executer()
    Command = exe.AddCommand("Yeah 0")
    exe.AddCommand("Yeah 1")
    exe.AddCommand("Yeah 2")
    exe.AddCommand("Yeah 3")
    exe.AddCommand("Yeah 4")
    x = Command.GetValue()
    print(x)
    print("Done")

Похоже, та же проблема, что и здесь: Поток Python. Поток, области и сборка мусора

Хотя решение (в его комментариях) кажетсяработать на автора, это не работает для меня после его интеграции. Основной поток будет выполняться через все мои команды, но подзаголовок не умрет, так как класс "executeer" не будет удален.

Класс будет удален, если пользователь специально вызвалdel exe, но это не очень хороший подход к Python, так как пользователю моего пакета всегда нужно будет самостоятельно очищать класс.

...