You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多进程共享列表追加进程后返回值未更新问题求助

问题原因分析
  • 跨Manager代理兼容性问题:你在processing_task内新建了独立的BaseManager创建进程代理,而外部共享列表由另一个Manager实例生成。不同Manager的代理对象无法在彼此的共享容器中正常同步状态,导致外部看不到列表更新。
  • 热键绑定错误:keyboard.add_hotkey('ctrl+shift+q', kill_all(a_processes=xzy))会立即执行kill_all,而非触发热键时才执行,属于参数传递方式错误。
  • 冗余返回值处理:共享列表本身就是进程间同步的,无需返回修改后的列表,直接使用原对象即可。
修复后的完整代码
from multiprocessing import Manager, Process
from multiprocessing.managers import NamespaceProxy, BaseManager
import inspect
import time
import keyboard
import os


class ObjProxy(NamespaceProxy):
    """Returns a proxy instance for any user defined data-type. The proxy instance will have the namespace and
    functions of the data-type (except private/protected callables/attributes). Furthermore, the proxy will be
    pickable and can its state can be shared among different processes. """

    @classmethod
    def populate_obj_attributes(cls, real_cls):
        DISALLOWED = set(dir(cls))
        ALLOWED = ['__sizeof__', '__eq__', '__ne__', '__le__', '__repr__', '__dict__', '__lt__',
                   '__gt__']
        DISALLOWED.add('__class__')
        new_dict = {}
        for (attr, value) in inspect.getmembers(real_cls, callable):
            if attr not in DISALLOWED or attr in ALLOWED:
                new_dict[attr] = cls._proxy_wrap(attr)
        return new_dict

    @staticmethod
    def _proxy_wrap(attr):
        """ This method creates function that calls the proxified object's method."""

        def f(self, *args, **kwargs):
            return self._callmethod(attr, args, kwargs)

        return f


# 全局统一注册Process代理,避免重复创建Manager
attributes = ObjProxy.populate_obj_attributes(Process)
ProcessProxy = type("ProcessProxy", (ObjProxy,), attributes)
BaseManager.register('Process', Process, ProcessProxy, exposed=tuple(dir(ProcessProxy)))


def processing_task(function, normal_processes, combat_processes, all_processes,
                    arguments=None, append="ALL"):
    # 使用全局注册的Manager实例
    manager = BaseManager()
    manager.start()
    
    if arguments is None:
        start_function = manager.Process(target=function)
    else:
        start_function = manager.Process(target=function, args=arguments)

    # 向共享列表追加进程代理
    if append == "ALL":
        all_processes.append(start_function)
        print(f"函数内的all_processes: {all_processes}")
    elif append == "no":
        normal_processes.append(start_function)
    elif append == "co":
        combat_processes.append(start_function)

    start_function.start()

    print(f"函数内的normal_processes: {normal_processes}, combat_processes: {combat_processes}, all_processes: {all_processes}")


def counting():
    for i in range(1, 10, 1):
        time.sleep(1)
        print(i)


def kill_all(a_processes):
    time.sleep(0.5)
    print(f"尝试终止进程: {a_processes}")
    for process in a_processes:
        process.terminate()
        process.join()
    os._exit(0)


if __name__ == '__main__':
    # 全局唯一Manager,统一管理共享列表和进程代理
    manager = BaseManager()
    manager.start()
    
    no_processes = manager.list()
    co_processes = manager.list()
    all_processes = manager.list()

    processing_task(counting, no_processes, co_processes, all_processes) 
    print(f"外部的all_processes: {all_processes}")

    # 用lambda延迟调用kill_all,确保热键触发时才执行
    keyboard.add_hotkey('ctrl+shift+q', lambda: kill_all(a_processes=all_processes))
    
    # 保持主进程存活,等待热键触发
    keyboard.wait()
关键修复点说明
  • 统一Manager上下文:整个程序只使用一个Manager实例,确保共享列表和进程代理属于同一个进程间通信环境,解决状态不同步问题。
  • 修正热键绑定逻辑:通过lambda表达式延迟kill_all的执行,保证只有触发热键时才会执行进程终止操作。
  • 简化代码逻辑:去掉冗余的列表返回值,直接使用原共享列表对象。
  • 优化进程终止流程:移除重复的kill()调用(terminate()已足够终止进程),保留join()确保进程资源被正确回收。

内容的提问来源于stack exchange,提问作者Ggjustice V

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 11:06:18