我是Actix的新手,我正在try 了解如何在一个线程上运行服务器并从另一个线程发送请求.

这就是我到目前为止掌握的代码

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

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

编辑:按照@Finomennis和@afce25的建议,我将代码更改为使用任务而不是线程,并将结果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.

推荐答案

您的代码有几个地方有问题;最大的错误是您永远不会.await%地使用run()方法.

仅因为这一点,您不能在普通线程中运行它,它必须存在于异步任务中.

因此,发生的情况是:

  • 您可以创建服务器
  • 服务器永远不会运行,因为它没有awaited
  • 您查询服务器以获取响应
  • 响应永远不会到来,因为服务器没有运行,所以您陷入了reqwest::get

相反,你应该做的是:

  • 启动服务器.

所以:

  • 您不需要向外传播服务器对象来停止它.您可以在将.handle() first移到任务中之前创建它.服务器句柄不包含对服务器的引用,而是基于智能指针.
  • NEVER%的人将同步通道与异步任务一起使用.它将阻塞运行库,死锁所有内容.(在您的第二个示例中,它工作的唯一原因是它很可能是一个多线程运行时,而您只死锁了一个运行时核心.仍然很糟糕.)
  • (也许)如果你用#[actix_web::main],不要用tokio::spawn.actix-web有自己的运行时,你需要用它来运行actix_web::rt::spawn.如果你想使用基于tokio的任务,你需要做#[tokio::main].actix-web与Tokio运行时兼容.(EDIT:Actix-Web mighttokio::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

Rust相关问答推荐

如何在Rust中在屏幕中间打印内容?

为什么在Rust struct 中只允许最后一个字段具有动态大小的类型

当rust中不存在文件或目录时,std::FS::File::Create().unwire()会抛出错误

防止cargo test 中的竞争条件

RUST应用程序正在退出,错误代码为:(退出代码:0xc0000005,STATUS_ACCESS_VIOLATION)

变量需要parse()中的显式类型

如何使用Actix Web for Rust高效地为大文件服务

Rust将String上的迭代器转换为&;[&;str]

UnsafeCell:它如何通知 rustc Select 退出基于别名的优化?

如何在 Rust 中编写一个通用方法,它可以接受任何可以转换为另一个值的值?

如何使用tracing-subscriberRust crate 构建多编写者、全局过滤订阅者

Rust 文件未编译到 dll 中

为什么我们有两种方法来包含 serde_derive?

Rust 异步循环函数阻塞了其他future 任务的执行

实现AsyncWrite到hyper Sender时发生生命周期错误

没有明确地说return会产生错误:match arms have incompatible types

str 和 String 的 Rust 生命周期

是否可以通过可变引用推进可变切片?

没有通用参数的通用返回

如何将 while 循环内的用户输入添加到 Rust 中的向量?