rust 在单独的线程上运行一个actixweb服务器

g6ll5ycj  于 2023-02-12  发布在  其他
关注(0)|答案(1)|浏览(163)

我是acix的新手,我正在尝试理解如何在一个线程上运行服务器,并从另一个线程发送请求。
这是我目前拥有的代码

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;
}

它编译得很好,但是在发送请求时卡住了。看起来服务器正在运行,所以我不知道为什么我没有得到响应。
编辑:按照@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;
}

这就解决了这个问题。我仍然很好奇是否可以在不同的线程上完成它,因为我不能在同步函数中使用await

izkcnapc

izkcnapc1#

您的代码中有几处错误;最大的一个问题是你从来没有.awaitrun()方法。
仅凭这一点,您就不能在普通线程中运行它,它必须存在于异步任务中。
结果是:

  • 您创建了服务器
  • 服务器永远不会运行,因为它没有得到await ed
  • 查询服务器以获得响应
  • 因为服务器不运行,所以响应不会出现,因此您会陷入reqwest::get

你应该做什么:

  • 启动服务器。

还有:

  • 你不需要传播服务器对象来停止它。你可以在把它移到任务之前先创建一个.handle()first。服务器句柄不包含对服务器的引用,而是基于智能指针。
      • 切勿**对异步任务使用同步通道。这将阻塞运行时,死锁所有内容。(它在第二个示例中起作用的唯一原因是它很可能是一个多线程运行时,而您只死锁了其中一个运行时内核。仍然很糟糕。)
  • 如果你使用#[actix_web::main],就不要使用tokio::spawnactix-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;
}
Response code: 404

相关问题