[英]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.