如何等待信号

问题描述 投票:0回答:2

我想创建一个 while 循环来等待并仅在收到信号时才继续

例如在 while.py 中

        while queue:
             #wait until signal
             #bla bla

当我点击 Flask 服务器上的按钮时,它应该向此循环发送信号以继续:在 main.py 中

         def alarm():
             #trigger loop to continue

有办法吗?

python multithreading signals
2个回答
1
投票

您需要了解简单的生产者-消费者示例,(参见源代码

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
之前,您将看到“队列中没有任何内容,但消费者将尝试消费”的打印语句,这解释了为什么您会收到错误。


0
投票

@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()
© www.soinside.com 2019 - 2024. All rights reserved.