简体   繁体   English

在Python 3可靠队列基于线程间通讯

[英]Reliable queue based inter-thread messaging in Python 3

I'm trying to use the queue.Queue() class to communicate between threads. 我正在尝试使用queue.Queue()类在线程之间进行通信。 I never had a problem with it in 2.x, but lately, it has seemed really unreliable to me in 3.x. 我从来没有在2.x中遇到过问题,但是最近,在3.x中对我来说似乎确实不可靠。

I start with a queue, as a global variable in a module. 我从队列开始,作为模块中的全局变量。 Both threads are in this module. 两个线程都在此模块中。

q = queue.Queue()

Thread 1 has a put command: 线程1具有put命令:

global q
q.put(“Hello”)

Thread 2 has a get command: 线程2有一个get命令:

global q
z = q.qsize()
q.get_nowait()

I can see in the pycdev debugger that 1 is not empty after the put, but the get is still returning empty and z is 0 before the get command. 我在pycdev调试器中看到在put之后1不是不为空,但是get仍然返回空,并且get命令之前z为0。 This seems really strange to me. 这对我来说真的很奇怪。 I suspected mismatched scopes, but can't figure out where this might be happening. 我怀疑范围不匹配,但无法弄清楚这可能在哪里发生。 Does anyone have an idea conditions could cause this? 有谁知道条件可能会导致这种情况?

Or is there a more reliable, recommended way of doing this? 还是有更可靠的建议方法?

Update. 更新。 I found the source of the problem and it is reproducable. 我找到了问题的根源,并且可以重现。 Here is runnable, sample code: 这是可运行的示例代码:

from bottle import route, run, response
import time
import sys
import threading
import queue

engineStartQueue = queue.Queue()

class EngineStarter(threading.Thread):

    def run(self):
        try:
            global engineStartQueue
            startParams = engineStartQueue.get_nowait()

            #let url handler return 
            engineStartQueue.put_nowait([200, "Starting..."])
            time.sleep(10.0)
        except Exception as e:
            fullerror = sys.exc_info()
            errorID = str(fullerror[0])
            errorMsg = str(fullerror[1])
            alertMessage = "%s, %s" %(errorID, errorMsg)
            engineStartQueue.push([500, alertMessage])


@route('/admin/start', method='POST')
def start():   
    try:
        global engineStartQueue
        engineStartQueue.put("Hello")
        starter = EngineStarter()
        starter.start()

        time.sleep(3.0)  #Give the EngineStarter instance a couple of seconds to read the queue and respond
        returnParams = engineStartQueue.get_nowait()

        response.status = returnParams[0]
        return(returnParams[1])
    except Exception as e:
        fullerror = sys.exc_info()
        errorID = str(fullerror[0])
        errorMsg = str(fullerror[1])
        returnStr = "Failed to start:  %s, %s" %(errorID, errorMsg)
        response.status = 500
        return returnStr

if __name__ == '__main__':
    run(host='localhost', port=8080)

It is a bottle app, with a fire and forget REST call. 这是一个瓶装应用,具有开火和忘记REST的功能。 There is url handler, a threadable object and a globally visible queue. 有URL处理程序,可线程化对象和全局可见队列。

The URL handler 1 - creates an instance of the threadable object, EngineStarter 2 - Passes "Hello" to the queue 3 - Starts the thread 4 - Waits 3 seconds and gets the response from the EngineStarter thread 5 - Returns the http response code to the caller URL处理程序1-创建可线程对象的实例,EngineStarter 2-将“ Hello”传递到队列3-启动线程4-等待3秒并从EngineStarter线程获取响应5-将http响应代码返回到呼叫者

The EngineStarter thread: 1 - Reads the queue 2 - Responds with an http ok if the thread is not empty and a 500 error otherwise 3 - The engine starter thread now waits 10 seconds, to simulate a long running background task on the server EngineStarter线程:1-读取队列2-如果线程不为空​​,则以http ok响应,否则返回500错误3-引擎启动器线程现在等待10秒,以模拟服务器上长时间运行的后台任务

If I start the script in the pydev debugger and then call the handler without any breakpoints set, I get an http 200 response after 3 seconds. 如果我在pydev调试器中启动脚本,然后在未设置任何断点的情况下调用处理程序,则3秒钟后会收到http 200响应。 This means that the scope was shared. 这意味着范围是共享的。

If I set a breakpoint before looking into the queue, it is empty. 如果在查看队列之前设置断点,则该断点为空。 If I set the breakpoint after looking into the queue, then get_nowait() picks up "Hello". 如果在查看队列后设置了断点,则get_nowait()会选择“ Hello”。

It seems as if breakpoints in the pydev debugger are affecting the scope somehow. 似乎pydev调试器中的断点正在某种程度上影响范围。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM