[英]Unable to write/read value to/from registered shared object with multiprocessing BaseManager server across multiple processes
所以我一直在使用multiprocessing
模块,即BaseManager时遇到一些麻烦。
要重现该问题,可以写入以下四个文件:
queue_manager.py
只是定义了我要服务的 BaseManager,以及连接到服务器的便利 function。# queue_manager.py
import multiprocessing
from multiprocessing.managers import BaseManager
ADDRESS = "127.0.0.1"
PORT = 50000
PASSWORD = "password"
class QueueManager(BaseManager):
pass
def connect_to_manager(names):
for name in names:
QueueManager.register(name + "_input_tasks")
manager = QueueManager(address=(ADDRESS, PORT), authkey=PASSWORD.encode('utf-8'))
manager.connect()
return multiprocessing.Manager().dict({name: getattr(manager, name + "_input_tasks")() for name in names})
server.py
。 在这里,我们希望能够为名为“foo”和“bar”的两个队列提供服务,我们可以通过调用之前定义的connect_to_manager()
function 跨进程获取它们。# server.py
from queue_manager import QueueManager, ADDRESS, PORT, PASSWORD
import queue
class Server:
@staticmethod
def serve(names):
print("Serving...")
for name in names:
QueueManager.register(name + "_input_tasks", callable=lambda: queue.Queue())
m = QueueManager(address=(ADDRESS, PORT), authkey=PASSWORD.encode('utf-8'))
s = m.get_server()
s.serve_forever()
def main(names):
Server.serve(names)
if __name__ == '__main__':
main(['foo', 'bar'])
workers.py
将由应该在这些队列上执行某些任务的多处理进程组成。 这里,我们只获取队列中的值并打印出来。# workers.py
import multiprocessing
from queue_manager import connect_to_manager, PASSWORD
import time
class MyProcess(multiprocessing.Process):
def __init__(self, input_queue):
multiprocessing.Process.__init__(self)
self.input_queue = input_queue
def run(self):
multiprocessing.current_process().authkey = PASSWORD.encode('utf-8')
while True:
time.sleep(1)
print("Running...")
if input_queue.empty():
print("Empty")
else:
x = input_queue.get()
print(x)
def create_workers(input_queue, n_workers):
p = MyProcess(input_queue)
p.start()
p.join()
if __name__ == '__main__':
multiprocessing.current_process().authkey = PASSWORD.encode('utf-8')
name_queue_mapping = connect_to_manager(['foo', 'bar'])
# assume we focus on foo queue
input_queue = name_queue_mapping['foo']
create_workers(input_queue, 1)
client.py
将一些值放入队列中# client.py
from queue_manager import connect_to_manager, PASSWORD
import multiprocessing
import time
def client():
multiprocessing.current_process().authkey = PASSWORD.encode('utf-8')
names = ['foo', 'bar']
name_queue_mapping = connect_to_manager(names)
foo_queue = name_queue_mapping["foo"]
bar_queue = name_queue_mapping["bar"]
for i in range(5):
time.sleep(1)
foo_queue.put(i)
if __name__ == '__main__':
client()
假设我们在不同的终端中同时运行最后三个文件中的每一个(并按此顺序):
python server.py
python client.py
python workers.py
问题是客户端成功地将值放入foo
队列中。 然而,他们并没有被workers
捡走。
现在避免这种情况的一种方法是不将 lambda function 传递给serve()
function 中的QueueManager.register()
调用。即像这样:
QueueManager.register(name + "_input_tasks", callable=get_foo_queue)
# where get_foo_queue is defined globally in the server.py file as such
# server.py
my_foo_queue = queue.Queue()
def get_foo_queue():
return my_foo_queue
class Server:
....
代替:
QueueManager.register(name + "_input_tasks", callable=lambda: queue.Queue())
但是,我不想这样做,因为我希望能够动态创建队列/函数,因为在运行之前我不知道它们的名称,也不知道我想要多少。 有任何想法吗?
首先,在文件workers.py方法run
中,您引用了变量input_queue
,这需要更改为self.input_queue
(参见最后一个清单)。
然后我会修改文件server.py以确保对于给定的队列名称(例如foo ), QueueManager
始终提供相同的singleton queue.Queue
实例。 在此更新的server.py文件中按如下方式执行此操作后...
更新了 server.py
# server.py
from queue_manager import QueueManager, ADDRESS, PORT, PASSWORD
import queue
queues = {}
def get_queue(queue_name):
def f():
return queues[queue_name]
return f
class Server:
@staticmethod
def serve(names):
print("Serving...")
for name in names:
queue_name = name + "_input_tasks"
q = queue.Queue()
queues[queue_name] = q
callable = get_queue(queue_name)
QueueManager.register(queue_name, callable)
m = QueueManager(address=(ADDRESS, PORT), authkey=PASSWORD.encode('utf-8'))
s = m.get_server()
s.serve_forever()
def main(names):
Server.serve(names)
if __name__ == '__main__':
main(['foo', 'bar'])
...然后更新的queue_manager.py文件变得简化为:
更新了 queue_manager.py
# queue_manager.py
import multiprocessing
from multiprocessing.managers import BaseManager
ADDRESS = "127.0.0.1"
PORT = 50000
PASSWORD = "password"
class QueueManager(BaseManager):
pass
def connect_to_manager(names):
for name in names:
QueueManager.register(name + "_input_tasks")
manager = QueueManager(address=(ADDRESS, PORT), authkey=PASSWORD.encode('utf-8'))
manager.connect()
return {name: getattr(manager, name + "_input_tasks")() for name in names}
为了更好地衡量,更正后的workers.py :
更正 workers.py
# workers.py
import multiprocessing
from queue_manager import connect_to_manager, PASSWORD
import time
class MyProcess(multiprocessing.Process):
def __init__(self, input_queue):
multiprocessing.Process.__init__(self)
self.input_queue = input_queue
def run(self):
multiprocessing.current_process().authkey = PASSWORD.encode('utf-8')
while True:
time.sleep(1)
print("Running...")
if self.input_queue.empty():
print("Empty")
else:
x = self.input_queue.get()
print(x)
def create_workers(input_queue, n_workers):
p = MyProcess(input_queue)
p.start()
p.join()
if __name__ == '__main__':
multiprocessing.current_process().authkey = PASSWORD.encode('utf-8')
name_queue_mapping = connect_to_manager(['foo', 'bar'])
# assume we focus on foo queue
input_queue = name_queue_mapping['foo']
create_workers(input_queue, 1)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.