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

Python中可否让websockets在后台运行并支持外部调用send方法

问题分析

你代码的核心问题有两个:

  • receive方法是无限循环,await handler.receive()会直接卡住整个Iao()协程,后续的send、close永远不会执行,同时loop.run_until_complete(Iao())会一直等待协程结束,导致后面的同步while循环完全无法运行
  • 后续你用asyncio.run()调用send会创建全新的独立事件循环,和承载websocket连接的旧事件循环完全隔离,必然调用失败
解决代码

不需要额外创建新的顶层async函数,用子线程单独跑asyncio事件循环即可实现需求,修改后代码如下:

import asyncio
import websockets
import time
import threading

class WebsocketHandler():
    def __init__(self):
        self.conn = None
        self.loop = None

    async def connect(self, url):
        self.conn = await websockets.connect(url)
        # 将receive作为后台任务运行,不阻塞当前协程
        asyncio.create_task(self.receive())

    async def send(self, msg):
        await self.conn.send(msg)
    
    async def receive(self):
        while True:
            print(await self.conn.recv())

    async def close(self):
        await self.conn.close()


async def Iao():
    global handler
    handler = WebsocketHandler()
    await handler.connect('ws://localhost:8765')
    # 保持协程运行不退出即可
    while True:
        await asyncio.sleep(3600)

# 子线程运行事件循环的函数
def run_loop():
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    handler.loop = loop
    loop.run_until_complete(Iao())

# 初始化handler并启动子线程跑事件循环
handler = None
threading.Thread(target=run_loop, daemon=True).start()
# 等待连接完成,可自行替换为更优雅的事件通知逻辑
time.sleep(1)

while True:
    print("1")
    # 跨线程提交协程任务到子线程的事件循环执行
    asyncio.run_coroutine_threadsafe(handler.send('{"action":"plus"}'), handler.loop).result()
    print("2")
    time.sleep(2)
核心说明
  • 单独启动子线程运行asyncio事件循环,不会阻塞主线程的同步业务逻辑
  • 连接完成后用asyncio.create_task()将receive转为后台任务,不会阻塞后续逻辑执行,同时可以持续监听消息并打印
  • 主线程要调用异步send方法时,使用asyncio.run_coroutine_threadsafe将协程提交到子线程的事件队列中,实现跨线程安全调用异步方法,满足其他函数调用send发消息的需求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 16:36:03