多进程共享列表追加进程后返回值未更新问题求助
问题原因分析
- 跨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
相关产品推荐
相关产品推荐

