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

Actix Web独立线程运行时请求无响应,能否用线程实现跨线程请求?

Actix跨线程运行服务器并发送请求的问题

问题背景

我是Actix新手,想要实现在一个线程中启动服务器,另一个线程发送请求的逻辑。

初始代码

use actix_web::{web, App, HttpResponse, HttpServer};
use std::{sync::mpsc::channel, thread};

#[actix_web::main]
async fn main() {
    let (tx, rx) = channel();
    thread::spawn(move || {
        let srv =
            HttpServer::new(|| App::new().default_service(web::to(|| HttpResponse::NotFound())))
                .bind("localhost:12347")
                .unwrap()
                .run();
        let _ = tx.send(srv);
    });
    reqwest::get("http://localhost:12347").await.unwrap();
    let srv = rx.recv().unwrap();
    srv.handle().stop(false).await;
}

问题现象

代码可正常编译,但发送请求时会卡住,无法得到响应。

修改后的可行代码(使用Tokio任务)

根据建议改用Tokio异步任务实现后,问题解决:

use actix_web::{web, App, HttpResponse, HttpServer};
use std::{sync::mpsc::channel, thread};

#[actix_web::main]
async fn main() {
    let (tx, rx) = channel();
    tokio::spawn(async move {
        let srv =
            HttpServer::new(|| App::new().default_service(web::to(|| HttpResponse::NotFound())))
                .bind("localhost:12347")
                .unwrap()
                .run();
        let _ = tx.send(srv.handle());
        srv.await.unwrap();
    });
    reqwest::get("http://localhost:12347").await.unwrap();
    let handle = rx.recv().unwrap();
    handle.stop(false).await;
}

疑问

虽然用异步任务解决了问题,但我仍好奇:是否可以用普通线程实现该逻辑?毕竟同步函数内无法直接使用await。


解答

初始代码卡住的原因

Actix的HttpServer::run()返回的是一个Server类型的异步Future,而普通线程中没有异步Runtime来驱动这个Future执行。所以你只是创建了Server对象,但服务器并没有真正启动,导致请求无法被处理,最终卡住。

用普通线程实现的方案

要在普通线程中运行Actix服务器,需要手动在新线程内初始化Actix的异步Runtime,然后在Runtime中执行Server的Future。示例代码如下:

use actix_web::{web, App, HttpResponse, HttpServer};
use std::{sync::mpsc::channel, thread};
use actix_rt::Runtime;

#[actix_web::main]
async fn main() {
    let (tx, rx) = channel();
    
    // 在普通线程中启动Actix Runtime并运行服务器
    thread::spawn(move || {
        // 初始化Actix Runtime
        let rt = Runtime::new().unwrap();
        let srv = HttpServer::new(|| App::new().default_service(web::to(|| HttpResponse::NotFound())))
            .bind("localhost:12347")
            .unwrap()
            .run();
        // 发送服务器句柄给主线程
        let _ = tx.send(srv.handle());
        // 在Runtime中await服务器运行的Future,阻塞线程直到服务器停止
        rt.block_on(srv).unwrap();
    });
    
    // 等待服务器启动后发送请求
    std::thread::sleep(std::time::Duration::from_millis(500));
    reqwest::get("http://localhost:12347").await.unwrap();
    
    // 获取服务器句柄并停止服务器
    let handle = rx.recv().unwrap();
    handle.stop(false).await;
}

说明

  • 普通线程中通过actix_rt::Runtime::new()创建Actix的异步Runtime,然后用rt.block_on()来阻塞执行Server的Future,这样服务器才能真正启动并处理请求。
  • 主线程发送请求前加了短暂延迟,是为了确保服务器已经完成启动并开始监听端口,避免请求过早发送导致失败(生产环境可以用更可靠的同步机制,比如通过mpsc等待服务器启动完成的信号)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 01:40:38