#python #multithreading #python-multithreading
#python #многопоточность #python-многопоточность
Вопрос:
В моем приложении у меня есть два потока. Основной и «поток». therad генерирует некоторые данные и сохраняет их в списке python. Основной поток периодически копирует содержимое списка, сгенерированного «потоком». Оба потока имеют бесконечный цикл while. Моя цель — остановить оба потока, когда я нажимаю любую клавишу enter. Для достижения этой цели программа должна ожидать ввода с клавиатуры во время выполнения потоков. Я подумал, что мне нужен другой поток (скажем, менеджер), который только ожидает ввода с клавиатуры во время выполнения. Вот что я попробовал сначала:
class managerThread(threading.Thread):
is_running = True
def __init__(self):
threading.Thread.__init__(self)
signal.signal(signal.SIGINT, self.kill_all)
signal.signal(signal.SIGTERM, self.kill_all)
def run(self):
input("Press any key enter to stop: ")
self.is_running = False
def kill_all(self,signum, frame):
print("Process ended with keyboard interrupt")
self.is_running = False
sys.exit(-1)
class thread(threading.Thread):
mgr = managerThread()
mgr.start()
def __init__(self):
threading.Thread.__init__(self)
def run(self):
while (self.mgr.is_running):
print("this is acquiring data")
sleep(2.5)
self.mgr.join()
print("manager stopped")
if __name__ == "__main__":
thread = thread()
thread.start()
while (thread.mgr.is_running):
print("this is copying data")
sleep(3)
thread.join()
print("thread is stopped")
sys.exit(0)
Приведенный выше код делает именно то, что я хочу сделать. Но это не кажется правильным. Менеджер управляет всеми остальными, но он создается в одном из подчиненных потоков. Другая проблема заключается в том, что можно попытаться создать несколько менеджеров в разных потоках. Этого следует строго избегать. Тогда я подумал, что менеджер должен наследоваться управляемыми классами. Вот что я попробовал:
class managerThread(threading.Thread):
is_running = True
def __init__(self):
threading.Thread.__init__(self)
signal.signal(signal.SIGINT, self.kill_all)
signal.signal(signal.SIGTERM, self.kill_all)
self.start()
def run(self):
input("Press any key enter to stop: ")
self.is_running = False
def kill_all(self,signum, frame):
print("Process ended with keyboard interrupt")
self.is_running = False
sys.exit(-1)
class thread(managerThread):
def __init__(self):
super().__init__()
threading.Thread.__init__(self)
def run(self):
while (self.is_running):
print("this is acquiring data")
sleep(2.5)
print("manager stopped")
if __name__ == "__main__":
thread = thread()
thread.start()
while (thread.is_running):
print("this is copying data")
sleep(3)
thread.join()
print("thread is stopped")
sys.exit(0)
Как видно из второго кода, основная часть та же. Я пытался сделать thread
как дочерний элемент managerThread
. Однако это не работает. Менеджер никогда не выполняет метод «run». Поэтому я не могу остановить другие потоки. Другая важная проблема заключается в том, что я не знаю, как остановиться super()
join()
. Я уверен, что совершаю ошибку в отношении наследования классов, но я не смог решить проблему, поскольку у меня не слишком много опыта работы с ООП, а потоки удвоили мое замешательство.
Примечание: меня не волнует синхронизация потоков.
Мои вопросы:
— Правильно ли создавать поток менеджера для безопасной остановки подчиненных потоков? Если нет, то как правильно?
— Почему второй код не работает? Что мне нужно изменить, чтобы заставить его работать?
— Почему родительский класс инициализируется, но он никогда не запускает метод «run»?
— Я считаю, что родительский класс никогда не запускается, но как я могу остановить его во втором коде, если он действительно запускается?
Спасибо.
Ответ №1:
Даже я не хотел использовать глобальную переменную для безопасной остановки всех потоков, я не мог найти решение без глобального флага запуска. Я также пытался передать изменяемую переменную в поток менеджера, но безуспешно. Вот рабочий набросок, который объясняет, как я решил свою проблему. Я надеюсь, что это поможет кому-то еще. Между тем, я был бы рад, если бы кто-нибудь предложил лучшее решение :).
Примечание: я не отлаживал его.
import sys
import threading, queue
import signal
from time import sleep
import numpy as np
global_running = False
class managerThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
signal.signal(signal.SIGINT, self.kill_all)
signal.signal(signal.SIGTERM, self.kill_all)
def run(self):
global is_running
is_running = True
input("Press any key enter to stop: ")
is_running = False
print("manager finished")
def kill_all(self,signum, frame):
global is_running
is_running = False
print("Process ended with keyboard interrupt")
sys.exit(-1)
class thread(threading.Thread):
__mgr = managerThread()
__mgr.start()
running = True
def __init__(self):
threading.Thread.__init__(self)
self.myvar = 0
self.queue = queue.Queue()
def currentVar(self):
var = np.empty(1)
while (var.size<=1):
var = self.queue.get()
self.queue.task_done()
return var
def run(self):
global is_running
while (is_running):
print("this is acquiring data")
sleep(2.5)
self.myvar = np.empty(5)
self.queue.put(self.myvar)
self.running = False
self.__mgr.join()
print("manager stopped")
if __name__ == "__main__":
thread = thread()
thread.start()
while (thread.running):
# var = thread.queue.get()
var = thread.currentVar()
print ("value is: ", var)
# thread.queue.task_done()
thread.join()
print("thread is stopped")
sys.exit(0)