Как убить мой поток при выходе из скрипта Python (если мне нужно)? - PullRequest
0 голосов
/ 04 июля 2019

Я разрабатываю программу, которая извлекает данные из API каждую секунду. Итак, у меня есть функция, которая называется тик, которая в основном возвращает данные из API. Чтобы иметь возможность использовать графический интерфейс без остановки каждую секунду во время ожидания ответа, я поместил его в поток, например так:

def every(delay, task):
  next_time = time.time() + delay
  while True:
    time.sleep(max(0, next_time - time.time()))
    try:
      task()
    except Exception:
      traceback.print_exc()
      # in production code you might want to have this instead of course:
      # logger.exception("Problem while executing repetitive task.")
    # skip tasks if we are behind schedule:
    next_time += (time.time() - next_time) // delay * delay + delay

    ...
    ...

threading.Thread(target=lambda: every(1, tick)).start()

window.mainloop()

Когда я закрываю окно GUI, консоль python сходит с ума так:

Traceback (последний вызов был последним): File «D: /PycharmProjects/test/test.py», строка 22, в каждом Файл task () «D: /PycharmProjects/test/test.py», строка 66, в галочке insert_text (unn1, unn_text) Файл "D: /PycharmProjects/test/test.py", строка 47, в insert_text entry.delete (0, END) Файл "D: \ Python37 \ lib \ tkinter__init __. py", строка 2676, в удалении self.tk.call (self._w, 'delete', first, last) RuntimeError: основной поток не находится в основном цикле

Мне ясно, что поток не заканчивается. Но я новичок в python и потоке, поэтому я не знаю, нужно ли этот поток закрывать из кода или если я на самом деле запускаю скомпилированную программу, она автоматически закроет его, когда я закрою окно программы. Итак, мне нужно закрыть его изнутри? Если да, то как мне сделать это правильно?

1 Ответ

1 голос
/ 04 июля 2019

Вы можете использовать глобальную переменную (т. Е. running) для управления while петлей.

После этого вы также можете использовать thread.join() для ожидания окончания потока.

def every(delay, task):
  global running 

  next_time = time.time() + delay

  while running:
      ...
      ...

#---------------------------------------------

running = True
thread = threading.Thread(target=lambda: every(1, tick))
thread.start()

window.mainloop()

running = False # it will end `while` loop
thread.join()   # it will wait for end of thread

Если task долго не получается, вы можете использовать after() вместо нити и while цикл. Нечто похожее на

def every(delay, task):
    start = time.time()

    try:
       task()
    except Exception:
       traceback.print_exc()

    end = time.time()
    diff = end - start
    after_time = max(0, delay - diff)

    if running:
        window.after(after_time, every, (1000, task)) # 1000ms=1s

#---------------------------------------------

running = True

window.every(1000, tick) # 1000ms=1s
window.mainloop()

running = False # it will end `while` loop
...