如何在不传递引用的情况下与 Python 中的 SyncManager 跨进程共享列表

How do I share a list across processes with SyncManager in Python without passing references

在python中,多处理模块提供了可以在进程之间生成共享lists/dicts的管理器。

但是,如果访问管理器的进程不是子进程,而是通过 Manager.connect 连接到管理器,我在使用这些共享对象时遇到问题。

这是一个非常基本的示例:我正在尝试创建一个可以由一组进程访问的共享列表。对于这个例子,我只是在两个终端 windows:

中两次启动相同的代码
import os, time
from multiprocessing.managers import SyncManager
            
def main() -> None:
    print(f"I am process {os.getpid()}")
    print(f"Starting proxy server...")
 
    manager = SyncManager(address=("127.0.0.1", 8000), authkey=b"noauth")
    try:
        manager.start() # will start the sync process if it doesn't exist
    except:
        manager.connect() # if it does already exist, connect to it instead
 
    print(f"Proxy server started/connected")
 
    # would like to generate a shared list that each process can access.
    sharedList = manager.list() # this generates a new list, so each process gets their own, which is not what I want
 
    sharedList.append(os.getpid())
 
    time.sleep(20)
 
if __name__ == '__main__':
    main()

Python documentation on using remote managers 似乎与我正在寻找的相似,但没有关于如何获得 Manager.listManager.dict 共享的信息。

注意:我也非常乐意共享命名空间对象。

以下是我最终解决问题的方法。您需要手动生成一个拥有共享列表的管理器进程。

import multiprocessing
from multiprocessing import process
import os, time, sys
from multiprocessing.managers import SyncManager, ListProxy
from queue import Queue

class SharedStorage(SyncManager):
    pass

def ManagerProcess():
    sys.stdout = open(os.devnull, 'w') 
    sys.stderr = open(os.devnull, 'w') 

    l = list()

    SharedStorage.register('get_list', lambda: l, ListProxy)
    try: 
        ss = SharedStorage(address=("127.0.0.1", 8000), authkey=b"noauth")
        ss.get_server().serve_forever()
    except OSError:
        # failed to listen on port - already in use.
        pass

def main() -> None:
    print(f"I am process {os.getpid()}")
    print(f"Starting proxy server...")

    mainProcess = multiprocessing.Process(target=ManagerProcess, daemon=True)
    mainProcess.start()

    SharedStorage.register('get_list')
    manager = SharedStorage(address=("127.0.0.1", 8000), authkey=b"noauth")
    manager.connect()

    print(f"Proxy server started/connected")

    # required - see https://bugs.python.org/issue7503
    multiprocessing.current_process().authkey = b"noauth"

    # get reference to the shared list object
    shared_list = manager.get_list()

    shared_list.append(os.getpid())

    for i in shared_list:
        print(i)

    time.sleep(20)

if __name__ == '__main__':
    main()

这可以安全地 运行 几次,因为后面的进程派生的管理器进程将在无法侦听端口后退出。