我想创建一个 while 循环来等待并仅在收到信号时才继续
例如在 while.py 中
while queue:
#wait until signal
#bla bla
当我点击 Flask 服务器上的按钮时,它应该向此循环发送信号以继续:在 main.py 中
def alarm():
#trigger loop to continue
有办法吗?
您需要了解简单的生产者-消费者示例,(参见源代码)
from threading import Thread, Lock
import time
import random
queue = []
lock = Lock()
class ProducerThread(Thread):
def run(self):
nums = range(5) #Will create the list [0, 1, 2, 3, 4]
global queue
while True:
num = random.choice(nums) #Selects a random number from list [0, 1, 2, 3, 4]
lock.acquire()
queue.append(num)
print "Produced", num
lock.release()
time.sleep(random.random())
class ConsumerThread(Thread):
def run(self):
global queue
while True:
lock.acquire()
if not queue:
print "Nothing in queue, but consumer will try to consume"
num = queue.pop(0)
print "Consumed", num
lock.release()
time.sleep(random.random())
ProducerThread().start()
ConsumerThread().start()
说明:
我们启动了1个生产者线程(以下简称生产者)和1个消费者线程(以下简称消费者)。生产者不断向队列添加数据,而消费者不断从队列中删除数据。由于
queue
是一个共享变量,我们将其保留在锁内以避免竞争条件。
在某个时刻,消费者已经消费完所有东西,而生产者仍在睡觉。消费者试图消费更多,但由于
queue
是空的,因此 IndexError
升高。但在每次执行时,在引发 IndexError
之前,您将看到“队列中没有任何内容,但消费者将尝试消费”的打印语句,这解释了为什么您会收到错误。
@developer_hatch 的
time.sleep(random.random())
解决方案是一个“友好”的忙碌等待解决方案。恕我直言,这是不好的做法,或者充其量是不优雅的。
最好使用
Condition
对象,它们允许获取锁,然后释放它直到满足条件。
我还建议尽可能使用
with
语法以提高可读性并避免忘记发布。
import time
import numpy as np
from threading import Thread, Condition
queue = []
lock = Condition() # Condition, rather than Lock
class Producer(Thread):
def run(self):
global queue
while True:
time.sleep(np.random.rand())
task = f'some task {np.random.randint(0, 100)}'
with lock:
queue.append(task)
print(f"Produced: {task}")
lock.notify() # Notifies other threads the condition might be changed, i.e. `wait`/`wait_for` will get a turn.
class Consumer(Thread):
def run(self):
global queue
while True:
with lock:
lock.wait_for(lambda: len(queue) > 0) # Temporarily unlocks, such that other threads alter the condition
print(f"Consumded: {queue.pop()}")
time.sleep(np.random.rand())
Producer().start()
Consumer().start()