带队列的Python线程:如何避免使用join?

带队列的Python线程:如何避免使用join?,python,linux,multithreading,queue,can-bus,Python,Linux,Multithreading,Queue,Can Bus,我有一个包含两个线程的场景: 等待来自嵌入在C库阻塞调用中的套接字的消息的线程是Barra.ricevi,然后将一个元素放入队列 等待从队列中获取元素并执行某些操作的线程 示例代码 import Barra import Queue import threading posQu = Queue.Queue(maxsize=0) def threadCAN(): while True: canMsg = Barra.ricevi("can0"

我有一个包含两个线程的场景:

等待来自嵌入在C库阻塞调用中的套接字的消息的线程是Barra.ricevi,然后将一个元素放入队列

等待从队列中获取元素并执行某些操作的线程

示例代码

import Barra
import Queue    
import threading

posQu = Queue.Queue(maxsize=0)

def threadCAN():
    while True:
        canMsg = Barra.ricevi("can0")
        if canMsg[0] == 'ERR':
            print (canMsg)
        else:
            print ("Enqueued message"), canMsg
            posQu.put(canMsg)

thCan = threading.Thread(target = threadCAN)
thCan.daemon = True
thCan.start()

while True:
    posMsg = posQu.get()
    print ("Messagge from the queue"), posMsg
结果是,每次从套接字发出新消息时,都会向队列中添加一个新元素,但应该从队列中获取项目的主线程永远不会被唤醒

输出如下:

排队消息

排队消息

排队消息

排队消息

我希望:

排队消息

队列中的消息

排队消息

队列中的消息

解决此问题的唯一方法是添加线:

posQu.join()
posQu.task_done()
在等待套接字消息的线程末尾,以及行:

posQu.join()
posQu.task_done()
在主线程的末尾

在这种情况下,在从套接字接收到新消息之后,线程将阻塞,等待主线程处理排队项目

不幸的是,这不是期望的行为,因为我希望线程总是准备好从套接字获取消息,而不是等待作业从另一个线程完成

我做错了什么? 谢谢

安德鲁
意大利

这可能是因为您的Barra在Barra.ricevi时没有释放全局解释器锁GIL。不过,您可能需要检查一下

GIL确保在任何时间只能运行一个线程,从而限制了多处理器系统中线程的可用性。GIL每隔100个滴答声切换线程—一个滴答声松散地映射到字节码指令。有关更多详细信息,请参阅

在producer线程中,除了C-library调用之外,不会发生太多事情。这意味着在GIL切换到另一个线程之前,生产者线程将多次调用Barra.ricevi

解决这一问题的办法是,在日益复杂的情况下:

将项目添加到队列后调用time.sleep0。这将生成线程,以便另一个线程可以运行。 在切换线程之前,使用sys.setcheckinterval降低执行的勾号量。这将以使程序在计算上更加昂贵为代价。 使用多处理而不是线程。这包括使用multiprocessing.Queue而不是Queue.Queue。 修改Barra,使其在调用其函数时释放GIL。 使用多处理的示例。请注意,使用多处理时,进程不再具有隐含的共享状态。您需要了解多进程,以了解如何在进程之间传递信息

import Barra  
import multiprocessing

def threadCAN(posQu):
    while True:
        canMsg = Barra.ricevi("can0")
        if canMsg[0] == 'ERR':
            print(canMsg)
        else:
            print("Enqueued message", canMsg)
            posQu.put(canMsg)

if __name__ == "__main__":
    posQu = multiprocessing.Queue(maxsize=0)
    procCan = multiprocessing.Process(target=threadCAN, args=(posQu,))
    procCan.daemon = True
    procCan.start()

    while True:
        posMsg = posQu.get()
        print("Messagge from the queue", posMsg)

你能给我们一个独立的例子,不需要Barra库吗?因为当我用只给它一个随机值的代码替换它时,它的工作方式和你希望的一样。因此我怀疑其他代码中存在问题,而不是此代码。由于Pastebin现在似乎已关闭,因此我的更改如下:将import Barra替换为import random,将canMsg=Barra.cicevican0替换为canMsg=['ERR']如果random.random<.25 else[0,1,2],然后运行代码,您将看到队列和消息经常在同一条线上交错。此外,CAN总线是否与该程序有任何关系?也许您使用的嵌入式linux系统没有pthread,所以它使用的是虚拟线程?这可能会导致这个问题……根据您在评论中给出的更改,我无法重现这个问题。我收到关于排队和退队的消息。然而,这可能与一个奇怪的、在您的情况下是故障的日程安排有关。也许writer线程从来没有放弃过处理器,而系统正因为如此和一个糟糕的调度机制从来没有激活reader线程。您是否尝试过使用Queue1而不是Queue0?这可能会使writer线程在尝试将第二条消息放入队列时立即进入睡眠状态。太好了!!谢谢。是吉尔!在I/O阻塞调用前后,我已经更改了我的Barra库,添加了宏:Py_BEGIN_ALLOW_线程和Py_END_ALLOW_线程。