Python类中使用multiprocessing报Cannot pickle weakref对象错误
问题根源
你遇到的Cannot pickle 'weakref' object异常,本质是Python多进程启动时的序列化限制:当你把类实例方法作为mp.Process的目标函数,并且传入self对象时,整个类实例会被尝试序列化(pickle)以传递给子进程。而你的ClientHandler实例中包含了manager、lock这类对象,它们内部依赖weakref(比如Manager的代理对象会用弱引用跟踪父进程连接),而weakref是无法被pickle序列化的。
哪怕你把manager、lock移到类外传入,只要传递了整个self对象,实例中任何不可序列化的成员(或其内部引用)都会触发这个异常。第一次启动进程时可能暂时避开,但第二次循环时实例状态变化,彻底触发序列化失败。
解决方案
核心思路是避免传递整个类实例给子进程,只传递子进程需要的独立参数,同时把进程执行逻辑改成不依赖实例的独立函数或静态方法。
方案1:使用全局独立函数
把进程处理逻辑抽成全局函数,仅传入子进程需要的参数(如客户端名、共享列表、锁),完全避开类实例的序列化:
import multiprocessing as mp # 独立的进程处理函数,不依赖类实例 def process_client(client, shared_list, lock): with lock: shared_list.append(f"Processed {client}") print(f"Completed handling {client}") class ClientHandler: def __init__(self, client_dict): self.processes = [] self.manager = mp.Manager() self.shared_list = self.manager.list() self.lock = mp.Lock() if "ServerGroup" in client_dict and client_dict["ServerGroup"]: for client in client_dict["ServerGroup"]: # 传入独立函数和必要参数,不传self proc = mp.Process(target=process_client, args=(client, self.shared_list, self.lock)) self.processes.append(proc) def start(self): for proc in self.processes: proc.start() # 可选:等待所有进程结束 for proc in self.processes: proc.join()
方案2:使用类静态方法
如果希望逻辑和类绑定,可以用静态方法(不需要实例引用),同样只传必要参数:
import multiprocessing as mp class ClientHandler: def __init__(self, client_dict): self.processes = [] self.manager = mp.Manager() self.shared_list = self.manager.list() self.lock = mp.Lock() if "ServerGroup" in client_dict and client_dict["ServerGroup"]: for client in client_dict["ServerGroup"]: # 调用静态方法,传入参数 proc = mp.Process(target=ClientHandler._process_client, args=(client, self.shared_list, self.lock)) self.processes.append(proc) @staticmethod def _process_client(client, shared_list, lock): with lock: shared_list.append(f"Processed {client}") print(f"Completed handling {client}") def start(self): for proc in self.processes: proc.start() for proc in self.processes: proc.join()
关键注意点
- 永远不要把整个类实例(
self)传给子进程,只传递子进程必须的、可序列化的参数。 mp.Manager创建的共享对象(如list、dict)本身是可跨进程传递的代理对象,直接传入即可,不需要包裹在实例里。- 避免在进程目标函数中使用绑定到实例的方法,除非你能确保整个实例完全可序列化(这在包含多进程原语时几乎不可能)。
内容的提问来源于stack exchange,提问作者Berat Yilmaz
相关产品推荐
相关产品推荐

