Как изменить значение аргумента в запущенном потоке в Python
Как изменить параметр функции, выполняющейся в бесконечном цикле в потоке (python)? Я новичок в потоках и Python, но это то, что я хочу сделать (упрощенно),
class myThread (threading.Thread):
def __init__(self, i):
threading.Thread.__init__(self)
def run(i):
self.blink(i)
def blink(i):
if i!=0:
if i==1:
speed=0.10
elif i==2:
speed=0.20
elif i==3:
speed=0.30
while(true):
print("speed\n")
i=3
blinkThread=myThread(i)
blinkThread.start()
while(i!=0):
i=input("Enter 0 to Exit or 1/2/3 to continue\n")
if i!=0:
blinkThread.run(i)
Теперь, очевидно, этот код выдает ошибки, касающиеся метода run(). Я хочу запустить функцию blink() в бесконечном цикле, но изменить переменную 'i'. Я также не могу сделать это без потока, потому что у меня есть другие части кода, которые выполняют параллельные задачи. Что я могу сделать? Спасибо!
2 ответа
Лучше всего сначала научиться никогда не менять переменные из разных потоков. Общаться через очереди:
import threading
import queue
def drive(speed_queue):
speed = 1
while True:
try:
speed = speed_queue.get(timeout=1)
if speed == 0:
break
except queue.Empty:
pass
print("speed:", speed)
def main():
speed_queue = queue.Queue()
threading.Thread(target=drive, args=(speed_queue,)).start()
while True:
speed = int(input("Enter 0 to Exit or 1/2/3 to continue: "))
speed_queue.put(speed)
if speed == 0:
break
main()
Помимо множества синтаксических ошибок, вы неправильно подходите ко всему процессу - нет смысла делегировать работу от запуска к другому методу, но даже если последний был, while
будет цикл бесконечно (если бы он был на самом деле написан как while True:
никогда не проверяю изменение скорости.
Кроме того, не используйте run()
метод взаимодействия с вашим потоком - это специальный метод, который вызывается при запуске потока, вы должны обрабатывать свои собственные обновления отдельно.
Вы также должны посвятить некоторое время изучению ООП в Python, так как это не то, как вы создаете класс.
Вот пример, который делает то, что вы хотите, надеюсь, это может помочь вам:
import threading
import time
class MyThread (threading.Thread):
def __init__(self, speed=0.1):
self._speed_cache = 0
self.speed = i
self.lock = threading.RLock()
super(MyThread, self).__init__()
def set_speed(self, speed): # you can use a proper setter if you want
with self.lock:
self.speed = speed
def run(self):
while True:
with self.lock:
if self.speed == 0:
print("Speed dropped to 0, exiting...")
break
# just so we don't continually print the speed, print only on change
if self.speed != self._speed_cache:
print("Current speed: {}".format(self.speed))
self._speed_cache = self.speed
time.sleep(0.1) # let it breathe
try:
input = raw_input # add for Python 2.6+ compatibility
except NameError:
pass
current_speed = 3 # initial speed
blink_thread = MyThread(current_speed)
blink_thread.start()
while current_speed != 0: # main loop until 0 speed is selected
time.sleep(0.1) # wait a little for an update
current_speed = int(input("Enter 0 to Exit or 1/2/3 to continue\n")) # add validation?
blink_thread.set_speed(current_speed)
Также обратите внимание, что многопоточность не выполняет ничего параллельно - она использует GIL для переключения между контекстами, но никогда не бывает двух потоков, выполняющихся в одно и то же время. Мьютекс (блокировка) в этом смысле предназначен только для обеспечения атомарности операций, а не фактической исключительности.
Если вам нужно что-то для параллельного выполнения (если у вас более одного ядра), вам нужно использовать multiprocessing
вместо.