Как изменить значение аргумента в запущенном потоке в 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 вместо.

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