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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 17:55:06