无限穿线

时间:2018-05-06 16:46:50

标签: python multithreading

我正在阅读Python documentationthis book中的Queue,我并不完全理解为什么我的帖子会挂起。我有以下mcve

from threading import Thread
import queue


def print_number(number_queue_display):

    while True:
        number = number_queue_display.get()
        print(number)
        number_queue_display.task_done()


number_queue = queue.Queue()
printing_numbers = Thread(target=print_number, args=(number_queue,),)
printing_numbers.start()

number_queue.put(5)
number_queue.put(10)
number_queue.put(15)
number_queue.put(20)

number_queue.join()
printing_numbers.join()

它唯一有效的时间是我将线程设置为守护进程,如下所示:

printing_numbers.setDaemon(True)

但这是因为如Python文档中所述,the program will exit只剩下守护程序线程。 Queue的Python文档示例不使用守护程序线程。

  

线程可以标记为“守护程序线程”。这个的意义   flag是只有守护进程线程时整个Python程序退出   离开了。

即使我要删除这两个联接(number_queue.join() printing_numbers.join()),它仍然会挂起,但我不确定原因。

问题:

  1. 为什么要挂?
  2. 如何将其保留为非守护程序线程,但防止它挂起?

1 个答案:

答案 0 :(得分:2)

print_number()正在运行一个无限循环 - 它永远不会退出,所以线程永远不会结束。它永远位于number_queue_display.get(),等待从未出现的另一个队列项。然后,由于线程永远不会结束,printing_numbers.join()也会永远等待。

所以你需要一些方式告诉线程退出。一种常见的方法是设置一个特殊的"哨兵"队列中的值,并在看到它时让线程退出。具体而言,这是一个完整的程序,与您开始时的程序非常相似。 None用作标记(并且通常用于此目的),但任何唯一对象都可以使用。请注意,.task_done()部分已被删除,因为它们不再用于某个目的。

from threading import Thread
import queue

def print_number(number_queue_display):

    while True:
        number = number_queue_display.get()
        if number is None:
            break
        print(number)


number_queue = queue.Queue()
printing_numbers = Thread(target=print_number, args=(number_queue,),)
printing_numbers.start()

number_queue.put(5)
number_queue.put(10)
number_queue.put(15)
number_queue.put(20)
number_queue.put(None)  # tell the thread it's done

printing_numbers.join() # wait for the thread to exit