在不同模块之间共享队列实例 [英] Sharing a Queue instance between different modules

查看:54
本文介绍了在不同模块之间共享队列实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是Python的新手,我想在不同模块中创建的线程/进程之间创建一个全局静态变量",即我的线程安全和进程安全队列.我从doc ,它是使用第三个模块(称为cfg)创建的,它定义并初始化了我的全局队列,该概念是使用第三个模块创建的.我在模块之间共享此对象的实例时遇到问题,因为我尝试在从cfg模块导入的共享队列中,在导入该对象的其他模块中打印 repr ()函数.表明它们是不同的实例.似乎每次我尝试导入模块时,都会创建一个新实例并将其传递给导入它的模块.

I am new to Python and I would like to create what is a 'global static variable', my thread-safe and process-safe queue, between threads/processes created in different modules. I read from the doc that the concept of a global variable is created using a third module, that I will call as cfg, which defines and initializes my global queue. I have a problem sharing the instance of this objects between my modules because I tried to print the repr() function over the shared queue imported from the cfg module, inside my other modules that import it, and it shows that they are different instances. It seems that every time I try to import a module a new instance is created and passed to the module who imports it.

Main.py:

import GatewayManager
if __name__ == '__main__':
    GatewayManager.initialize()
    doSomething()

GatewayManager.py:

GatewayManager.py:

import multiprocessing
import queue
import threading

def initialize():
    # Multiprocessing or Threading
    global isMonoCPU
    isMonoCPU = multiprocessing.cpu_count() == 1

    global sharedQueue
    sharedQueue = multiprocessing.Queue() if not isMonoCPU else queue.Queue()
    print("gateway: ", sharedQueue.__repr__())

otherModules.py:

otherModules.py:

import GatewayManager

# Some module write on the queue
GatewayManager.sharedQueue.put(variable)

# Some read from the queue
GatewayManager.sharedQueue.get()
print("driver: ", GatewayManager.sharedQueue.__repr__())

推荐答案

此处:

# GatewayManager.py:

...

def initialize():
    global sharedQueue
    # ...
    sharedQueue = multiprocessing.Queue()
    # ...

您的 GatewayManager 模块在调用 initialize()函数之前没有 sharedQueue 属性,因此,如果有其他模块尝试在调用 GatewayManager.initialize()之前使用 GatewayManager.sharedQueue ,那么您当然会得到此错误.而且由于 GatewayManager.initialize()在每次调用时盲目地重新绑定 sharedQueue ,因此,如果您从另一个模块再次调用它,则会丢失已经创建的队列并得到一个新的队列.

Your GatewayManager module don't have a sharedQueue attribute until it's initialize() function is called., so if any other module tries to use GatewayManager.sharedQueue before GatewayManager.initialize() has been called then of course you'll get this error. And since GatewayManager.initialize() blindly rebinds sharedQueue on each call, if you call it again from another module then you lose the already created queue and gets a new one.

您想要的是确保您的共享队列仅创建一次并且仅创建一次,并且无论发生什么情况都将创建该共享队列.这里的解决方案(至少是一个解决方案-但这是一个已知的有效解决方案)是代理所有 GatewayManager.sharedQueue.whatever 访问功能,这些功能将在需要时以及需要时初始化队列.

What you want is to make sure your sharedqueue is created once and only once, and that it will be created whatever happens. The solution (well, one solution at least - but it's a known working solution) here is to proxy all GatewayManager.sharedQueue.whatever access thru functions that will take care of initializing the queue if and when needed.

# gateway_manager.py

class _QueueProxy(object):
    def __init__(self):
        self._queueimp = None

    @property
    def _queue(self):
        if self._queueimp is None:
            isMonoCPU = multiprocessing.cpu_count() == 1
            self._queueimp = queue.Queue() if isMonoCPU else multiprocessing.Queue() 

        return self._queueimp

    def get(self, *args, **kw):
        return self._queue.get(*args, **kw)

    def put(self, *args, **kw):
        return self._queue.put(*args, **kw)

   # etc... only expose public methods and attributes of course


# and now our `shared_queue` instance    
shared_queue = _QueueProxy()

现在,您可以安全地(几乎-队列创建不是原子的,因此您可能会遇到竞争条件)从任何模块使用 gateway_manager.shared_queue ,而不必担心初始化.

And now you can safely (well almost - the queue creation is not atomic so you may have race conditions) use gateway_manager.shared_queue from any module without having to care about initialization.

当然,如果您有两个不同的进程(在这里我不是在谈论 multiprocessing.Process ),您仍然会有两个不同的队列,但是我想您已经了解了这一点(如果没有,请阅读让·保罗的答案).

Of course if you have two distinct processes (I'm not talking about multiprocessing.Process here) you will still have two distinct queues but I assume you already understood this (and if not please read Jean-Paul's answer).

这篇关于在不同模块之间共享队列实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆