Python类中用multiprocessing遇OSError:[WinError87]参数错误求助
解决Discord WebSocket连接类中多进程心跳任务的崩溃问题
问题场景
需为管理Discord WebSocket连接的Python类添加可终止的后台心跳阻塞任务,基础多进程代码可正常运行,但添加WebSocket连接逻辑后程序崩溃。
基础正常代码
import multiprocessing as mp import websocket import time class DiscordAgent: def connect(self): x = mp.Process(target=self.heartbeat) x.start() def heartbeat(self): while True: print("the heart is beating") time.sleep(1) if __name__ == "__main__": agent = DiscordAgent() agent.connect()
添加WebSocket后的崩溃代码
import multiprocessing as mp import websocket import time class DiscordAgent: def connect(self): self.ws = websocket.WebSocket() self.ws.connect( "wss://gateway.discord.gg/?encoding=json&v=9&compress=zlib-stream" ) x = mp.Process(target=self.heartbeat) x.start() def heartbeat(self): while True: print("the heart is beating") time.sleep(1) if __name__ == "__main__": agent = DiscordAgent() agent.connect()
报错信息
Traceback (most recent call last): File "f:\Coding\csj\polaris-back\test2.py", line 23, in <module> agent.connect() File "f:\Coding\csj\polaris-back\test2.py", line 13, in connect x.start() File "C:\Users\noahl\AppData\Local\Programs\Python\Python39\lib\multiprocessing\process.py", line 121, in start self._popen = self._Popen(self) File "C:\Users\noahl\AppData\Local\Programs\Python\Python39\lib\multiprocessing\context.py", line 224, in _Popen return _default_context.get_context().Process._Popen(process_obj) File "C:\Users\noahl\AppData\Local\Programs\Python\Python39\lib\multiprocessing\context.py", line 327, in _Popen return Popen(process_obj) File "C:\Users\noahl\AppData\Local\Programs\Python\Python39\lib\multiprocessing\popen_spawn_win32.py", line 93, in __init__ reduction.dump(process_obj, to_child) File "C:\Users\noahl\AppData\Local\Programs\Python\Python39\lib\multiprocessing\reduction.py", line 60, in dump ForkingPickler(file, protocol).dump(obj) File "C:\Users\noahl\AppData\Local\Programs\Python\Python39\lib\socket.py", line 273, in __getstate__ raise TypeError(f"cannot pickle {self.__class__.__name__!r} object") TypeError: cannot pickle 'SSLSocket' object (venv) PS F:\Coding\csj\polaris-back> Traceback (most recent call last): File "<string>", line 1, in <module> File "C:\Users\noahl\AppData\Local\Programs\Python\Python39\lib\multiprocessing\spawn.py", line 102, in spawn_main source_process = _winapi.OpenProcess( OSError: [WinError 87] The parameter is incorrect
错误原因
- Windows系统下
multiprocessing默认使用spawn方式创建子进程,该方式需要序列化(pickle)整个进程对象,包括其所属的类实例。 - 类实例中的
self.ws包含无法被pickle序列化的SSLSocket对象,导致序列化失败,程序崩溃。
解决方案
方案一:使用独立心跳函数+进程终止事件
将心跳逻辑改为独立函数,通过进程间事件(mp.Event)控制心跳终止,避免子进程持有类的WebSocket实例。
import multiprocessing as mp import websocket import time def heartbeat(stop_event): while not stop_event.is_set(): print("the heart is beating") time.sleep(1) class DiscordAgent: def __init__(self): self.stop_event = mp.Event() self.heartbeat_process = None def connect(self): self.ws = websocket.WebSocket() self.ws.connect( "wss://gateway.discord.gg/?encoding=json&v=9&compress=zlib-stream" ) # 启动心跳进程,传递终止事件 self.heartbeat_process = mp.Process(target=heartbeat, args=(self.stop_event,)) self.heartbeat_process.start() def disconnect(self): # 优雅终止心跳进程 if self.heartbeat_process: self.stop_event.set() self.heartbeat_process.join() # 关闭WebSocket连接 if hasattr(self, 'ws'): self.ws.close() if __name__ == "__main__": agent = DiscordAgent() agent.connect() try: # 模拟业务运行 time.sleep(5) finally: agent.disconnect()
方案二:修复线程终止问题(回到threading方案)
此前线程无法终止是因为缺少退出条件,通过threading.Event可以实现优雅终止:
import threading import websocket import time class DiscordAgent: def __init__(self): self.stop_event = threading.Event() self.heartbeat_thread = None def connect(self): self.ws = websocket.WebSocket() self.ws.connect( "wss://gateway.discord.gg/?encoding=json&v=9&compress=zlib-stream" ) self.heartbeat_thread = threading.Thread(target=self.heartbeat) self.heartbeat_thread.start() def heartbeat(self): while not self.stop_event.is_set(): print("the heart is beating") time.sleep(1) def disconnect(self): self.stop_event.set() if self.heartbeat_thread: self.heartbeat_thread.join() self.ws.close() if __name__ == "__main__": agent = DiscordAgent() agent.connect() try: time.sleep(5) finally: agent.disconnect()
方案三:使用进程管理器共享必要状态(如需访问WebSocket数据)
若心跳任务需要读取WebSocket的关键数据(如心跳间隔),可通过mp.Manager共享字典传递状态,避免直接传递WebSocket对象:
import multiprocessing as mp import websocket import time def heartbeat(stop_event, shared_state): while not stop_event.is_set(): print(f"the heart is beating, interval: {shared_state.get('interval', 1)}s") time.sleep(shared_state.get('interval', 1)) class DiscordAgent: def __init__(self): self.manager = mp.Manager() self.shared_state = self.manager.dict() self.stop_event = mp.Event() self.heartbeat_process = None def connect(self): self.ws = websocket.WebSocket() self.ws.connect( "wss://gateway.discord.gg/?encoding=json&v=9&compress=zlib-stream" ) # 从WebSocket响应中获取心跳间隔,存入共享状态 # 此处模拟获取间隔 self.shared_state['interval'] = 1 # 启动心跳进程 self.heartbeat_process = mp.Process(target=heartbeat, args=(self.stop_event, self.shared_state)) self.heartbeat_process.start() def disconnect(self): self.stop_event.set() if self.heartbeat_process: self.heartbeat_process.join() self.ws.close() self.manager.shutdown() if __name__ == "__main__": agent = DiscordAgent() agent.connect() try: time.sleep(5) finally: agent.disconnect()
内容的提问来源于stack exchange,提问作者Noah
相关产品推荐
相关产品推荐

