【问题标题】:How do I send data to a running python thread?如何将数据发送到正在运行的 python 线程?
【发布时间】:2014-09-18 05:08:36
【问题描述】:

我有一个在我的应用程序的单独线程中运行的类。我可以同时运行多个线程,这些线程是守护进程。一段时间后,这些线程中有一些需要接收和处理消息。我该怎么做?

我的代码示例如下所示:

import threading
import time 

class MyThread(threading.Thread):
    def __init__(self, args=(), kwargs=None):
        threading.Thread.__init__(self, args=(), kwargs=None)
        self.daemon = True
        self.receive_messages = args[0]

    def run(self):
        print threading.currentThread().getName(), self.receive_messages

    def do_thing_with_message(self, message):
        if self.receive_messages:
            print threading.currentThread().getName(), "Received %s".format(message)

if __name__ == '__main__':
    threads = []
    for t in range(10):
        threads.append( MyThread(args=(t % 2 == 0,)))
        threads[t].start()
        time.sleep(0.1)

    for t in threads:
        t.do_thing_with_message("Print this!")

这个输出:

Thread-1 True
Thread-2 False
Thread-3 True
Thread-4 False
Thread-5 True
Thread-6 False
Thread-7 True
Thread-8 False
Thread-9 True
Thread-10 False
MainThread Received %s
MainThread Received %s
MainThread Received %s
MainThread Received %s
MainThread Received %s

但是,我希望最后五行与MainThread 无关,而不是%s,我希望它与Print this! 相关,如下所示:

Thread-1 True
Thread-2 False
Thread-3 True
Thread-4 False
Thread-5 True
Thread-6 False
Thread-7 True
Thread-8 False
Thread-9 True
Thread-10 False
Thread-1 Received Print this!
Thread-3 Received Print this!
Thread-5 Received Print this!
Thread-7 Received Print this!
Thread-9 Received Print this!

我怎样才能正确地向正在运行的线程发送这样的消息?

附录:

如果我在Print this! 块之后有这个块,并利用@dano 的代码解决上述问题,它似乎没有响应这些新消息。

for t in threads:
    t.queue.put("Print this again!")
    time.sleep(0.1)

在这种情况下,我希望我的输出的结尾看起来像这样

Thread-1 Received Print this!
Thread-3 Received Print this!
Thread-5 Received Print this!
Thread-7 Received Print this!
Thread-9 Received Print this!
Thread-1 Received Print this again!
Thread-3 Received Print this again!
Thread-5 Received Print this again!
Thread-7 Received Print this again!
Thread-9 Received Print this again!

【问题讨论】:

  • 这就是 task queues 的设计目的。
  • @BurhanKhalid 我会说在这里使用像 Celery 这样的东西会有点矫枉过正。 Celery 对于将工作分配给集群中的多个进程或多台机器绝对有用,但这里更简单的东西将满足 OP 的需求。

标签: python multithreading


【解决方案1】:

您可以为此使用 Queue.Queue(或 Python 3 中的 queue.Queue):

import threading
import time 
from Queue import Queue

print_lock = threading.Lock()

class MyThread(threading.Thread):
    def __init__(self, queue, args=(), kwargs=None):
        threading.Thread.__init__(self, args=(), kwargs=None)
        self.queue = queue
        self.daemon = True
        self.receive_messages = args[0]

    def run(self):
        print threading.currentThread().getName(), self.receive_messages
        val = self.queue.get()
        self.do_thing_with_message(val)

    def do_thing_with_message(self, message):
        if self.receive_messages:
            with print_lock:
                print threading.currentThread().getName(), "Received {}".format(message)

if __name__ == '__main__':
    threads = []
    for t in range(10):
        q = Queue()
        threads.append(MyThread(q, args=(t % 2 == 0,)))
        threads[t].start()
        time.sleep(0.1)

    for t in threads:
        t.queue.put("Print this!")

    for t in threads:
        t.join()

我们将Queue 实例传递给每个线程,并使用queue.put 将我们的消息发送到Thread。我们等待消息到达run 方法,它是Thread 对象的一部分,实际上在单独的执行线程中运行。收到消息后,我们调用do_thing_with_message,它将在同一个后台线程中运行。

我还在代码中添加了threading.Lock,这样打印到标准输出的内容就不会混淆。

编辑:

如果您希望能够向线程传递多条消息,只需使用循环:

def run(self):
    print threading.currentThread().getName(), self.receive_messages
    while True:
        val = self.queue.get()
        if val is None:   # If you send `None`, the thread will exit.
            return
        self.do_thing_with_message(val)

【讨论】:

  • 这太棒了!它解决了我提出的问题,但可能并不完全符合我的预期。如果我添加另一个Print this! 循环(或任意数量的循环,因为我希望只要它们存在就能够向这些线程发送消息),则只有每个线程的第一条消息会打印。如何接受任意数量的消息? (如果这太多了,我可以提出一个单独的问题并将其标记为我原来问题的答案)
  • @PythonNoob 只需在val = self.queue.get() ; self.do_thing_with_message(val) 调用周围放置一个while True: 循环。
  • @PythonNoob 我已经编辑了我的答案以演示如何接收多条消息,以及如何通过放置一个标记值(None ) 进入Queue
猜你喜欢
  • 1970-01-01
  • 2014-07-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-04
  • 1970-01-01
  • 2011-02-10
  • 2015-09-28
相关资源
最近更新 更多