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

如何为客户端WebSocket的ping发送任务创建独立线程

问题原因

你代码的阻塞核心不是没做任务拆分,是在async任务块里调用了std::thread::sleep:

  • 这是同步阻塞调用,执行时会直接占住当前异步执行器的工作线程,4秒睡眠期间线程完全被挂起,根本不会调度执行其他任何异步任务。哪怕你用spawn把ping任务包了一层,只要它跑在公共异步工作线程上,就会堵死其他业务逻辑。
修复方案

根据实际需求二选一即可:

方案1:不额外开系统线程,改非阻塞实现(推荐,开销最低)

把同步阻塞的睡眠换成对应异步运行时提供的非阻塞睡眠即可,睡眠时任务会主动让出执行权,其他业务逻辑完全可以正常调度执行。你代码里用了Actix的Addr类型,直接用Actix-rt(或底层依赖的Tokio)的异步睡眠就行,修正后代码:

use std::time::Duration;
use actix::Addr;
use tracing::{info, warn};
// 注:需自行保证MicroscopeClient、Ping的Actor、Message trait实现已完成

pub fn sending_ping(addr: Addr<MicroscopeClient>) -> Result<(), ()> {
    info!("Pings started");

    actix_rt::spawn(async move {
        loop {
            info!("Ping");
            match addr.send(Ping {}).await {
                Ok(_) => info!("Ping sent"), // 原代码sended为拼写错误,修正为sent
                Err(e) => {
                    warn!("Ping send error: {e}");
                    return;
                }
            }
            // 替换同步阻塞睡眠为异步非阻塞睡眠,自动让出线程执行权
            actix_rt::time::sleep(Duration::from_millis(4000)).await;
        }
    });

    Ok(())
}

方案2:独立系统线程承载ping逻辑(完全隔离异步执行器)

如果确实要把ping逻辑和主业务的异步执行器完全隔离,就直接用标准库的线程接口派生独立系统线程,不要把带阻塞调用的逻辑塞到异步工作线程池里:

use std::time::Duration;
use actix::Addr;
use tracing::{info, warn};

pub fn sending_ping(addr: Addr<MicroscopeClient>) -> Result<(), ()> {
    info!("Pings started");

    // 派生独立系统线程,和主异步运行时完全隔离
    std::thread::spawn(move || {
        // 独立线程内初始化最小运行时,用来处理Actor消息的异步发送逻辑
        let rt = actix_rt::Runtime::new().unwrap();
        rt.block_on(async move {
            loop {
                info!("Ping");
                match addr.send(Ping {}).await {
                    Ok(_) => info!("Ping sent"),
                    Err(e) => {
                        warn!("Ping send error: {e}");
                        return;
                    }
                }
                // 独立线程内用同步睡眠没有任何问题,不会影响主业务
                std::thread::sleep(Duration::from_millis(4000));
            }
        })
    });

    Ok(())
}

补充:如果你用Tokio作为异步运行时,不要直接在tokio::spawn的任务里跑长阻塞逻辑,要跑阻塞任务请使用tokio::task::spawn_blocking,阻塞任务会被调度到专属的阻塞线程池,不会挤占普通异步任务的执行资源。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 07:30:49