在单独的线程上运行 actix Web 服务器

141*_*159 3 rust actix-web

我是 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;
}
Run Code Online (Sandbox Code Playgroud)

它编译得很好,但在发送请求时卡住了。看起来服务器正在运行,所以我不明白为什么我没有得到响应。

编辑:按照@Finomnis和@cafce25的建议,我更改了代码以使用任务而不是线程,并await编辑了结果.run()

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;
}
Run Code Online (Sandbox Code Playgroud)

这解决了问题。我仍然很好奇是否可以在不同的线程上执行此操作,因为我无法await在同步函数内使用。

Fin*_*nis 6

您的代码有一些问题;最大的一个是你没有.await方法run()

仅就这一事实而言,您无法在普通线程中运行它,它必须存在于异步任务中。

那么发生的事情是:

  • 你创建服务器
  • 服务器永远不会运行,因为它没有得到awaited
  • 您向服务器查询响应
  • 因为服务器没有运行,所以永远不会有响应,所以你陷入了困境reqwest::get

你应该做什么:

  • 启动服务器。

还:

  • 您不需要传播服务器对象来阻止它。.handle() 您可以先创建一个,然后再将其移至任务中。服务器句柄不包含对服务器的引用,而是基于智能指针。
  • 切勿将同步通道与异步任务一起使用。它会阻塞运行时,使一切陷入死锁。(它在第二个示例中起作用的唯一原因是因为它很可能是多线程运行时,并且您只死锁了其中一个运行时核心。仍然很糟糕。)
  • tokio::spawn(也许)如果你使用的话就不要这样做#[actix_web::main]actix-web有它自己的运行时,你需要actix_web::rt::spawn使用它。如果您想使用tokio基于任务,您需要执行#[tokio::main]. actix-web与 tokio 运行时兼容。(编辑:actix-web可能与兼容tokio::spawn(),我只是没有在任何地方找到说明它的文档)

完成所有这些修复后,这是一个工作版本:

use actix_web::{rt, web, App, HttpResponse, HttpServer};

#[actix_web::main]
async fn main() {
    let srv = HttpServer::new(|| App::new().default_service(web::to(|| HttpResponse::NotFound())))
        .bind("localhost:12347")
        .unwrap()
        .run();
    let srv_handle = srv.handle();

    rt::spawn(srv);

    let response = reqwest::get("http://localhost:12347").await.unwrap();
    println!("Response code: {:?}", response.status());

    srv_handle.stop(false).await;
}
Run Code Online (Sandbox Code Playgroud)
Response code: 404
Run Code Online (Sandbox Code Playgroud)