Python 2.7, thread.Timer создает слишком много мусорных потоков, которые не используются повторно

Я запускаю образец кода Python в своих окнах, после каждого выполнения потока таймера создается новый поток, как показано ниже, но старый никогда не перерабатывается, это действительно раздражает, количество потоков продолжает расти, и я боюсь, что мое программное обеспечение рано или поздно займет всю память компьютера. Я вижу, что многие другие также сталкивались с той же проблемой, при отладке с помощью pydev в конце концов будет сообщено «TclError: не хватает места в стеке»!

Вот список моего стека отладки pydev, он будет увеличиваться и увеличиваться до тех пор, пока "не закончится пространство стека", из представления стека я вижу, что количество потоков невероятно сумасшедшее ...

Thread-1913 - pid_9200_id_155817632
Thread-1915 - pid_9200_id_156052840 
Thread-1917 - pid_9200_id_156052112 
Thread-1919 - pid_9200_id_156326208 
Thread-1921 - pid_9200_id_156326264 

Ошибка, о которой сообщает pydev, выглядит следующим образом:

pydev debugger: starting (pid: 9200)
Exception in thread Thread-1921:
Traceback (most recent call last):
  File "C:\Python27\lib\threading.py", line 801, in __bootstrap_inner
    self.run()
  File "C:\Python27\lib\threading.py", line 1073, in run
    self.function(*self.args, **self.kwargs)
  File "D:\work\tools\eclipseWorkspace\timerTest.py", line 46, in handle_function
    self.hFunction()
  File "D:\work\tools\eclipseWorkspace\timerTest.py", line 56, in printer
    lab['text'] = clock
  File "C:\Python27\lib\lib-tk\Tkinter.py", line 1337, in __setitem__
    self.configure({key: value})
  File "C:\Python27\lib\lib-tk\Tkinter.py", line 1330, in configure
    return self._configure('configure', cnf, kw)
  File "C:\Python27\lib\lib-tk\Tkinter.py", line 1321, in _configure
    self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))
TclError: out of stack space (infinite loop?)

Ниже мой код, он устанавливает таймер, а затем вызывает функцию "цикл".

from threading import Timer, Thread, Event
from datetime import datetime
import Tkinter as tk

app = tk.Tk()
lab = tk.Label(app, text = "Timer will start in a sec")
lab.pack()

class perpetualTimer():

def __init__(self, t, hFunction):
    self.t = t
    self.hFunction = hFunction
    self.thread = Timer(self.t, self.loop)

def loop(self):
    self.hFunction()
    self.thread = Timer(self.t, self.loop)
    self.thread.start()

def start(self):
    self.thread.start()

def printer():
    tempo = datetime.today()
    clock = "{}:{}:{}".format(tempo.hour, tempo.minute, tempo.second)
    try:
        lab['text'] = clock
    except RuntimeError:
        exit()

t = perpetualTimer(0.1, printer)
t.start()
app.mainloop()

Если все, что вы делаете, это обновляете часы, вам определенно не нужно использовать потоки. Вы хотите решить проблему с потоками или открыты для других решений?

Bryan Oakley 31.10.2018 16:23

Привет @BryanOakley, я просто использую этот код, чтобы показать свою проблему, мне действительно не нужна функция «часы».

yunfei 01.11.2018 06:52
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
2
88
1

Ответы 1

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

class perpetualTimer():
    def __init__(self, t, hFunction):
        self.t = t
        self.hFunction = hFunction
        self.thread = Timer(self.t, self.handle_function)

    def handle_function(self):
        self.hFunction()
        self.thread = Timer(self.t, self.handle_function)
        self.thread.start()

    def start(self):
        self.thread.start()

Все потоки таймера завершаются после запуска и позже будут собраны мусором. Они не заполнят всю доступную память.

Привет, Джонатан, согласен, нет необходимости добавлять self.thread.cancel (), это было просто для отладки. Но ваш код работает так же, как и мой, он генерирует много мусорных потоков, я не вижу ни одного из них переработанного, но они все увеличиваются и увеличиваются, внешность никогда не достигает конца ...

yunfei 01.11.2018 06:46

Я только что внес некоторые изменения на основе ваших отзывов. Также я изменил время расписания с 1 секунды на 0,1, после чего я вижу, что идентификатор потока увеличился до 1929 «Thread-1929 - pid_4060_id_147668888»

yunfei 01.11.2018 07:22

Другие вопросы по теме