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

huangapple go评论64阅读模式
英文:

Running an actix web server on a separate thread

问题

以下是您提供的代码的中文翻译部分:

原始代码:

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

修改后的代码:

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

希望这有助于您理解代码和问题的解决方法。如果您有其他问题,可以随时提出。

英文:

I'm new to actix, and I'm trying to understand how I can run a server on one thread and send requests from another.

This is the code I have so far

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

It compiles just fine, but it gets stuck on on sending the request. It seems like the server is running, soI can't figure out why I am not getting a response.

EDIT: As suggested by @Finomnis and @cafce25,I changed the code to use tasks instead of threads, and awaited te result of .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;
}

which solves the problem. I'm still curious if it is possible to do it on different threads since I can't use await inside a synchronous function.

答案1

得分: 4

有几个问题你的代码; 其中最大的问题是你从未使用 .await 来执行 run() 方法。

因此,你不能在普通线程中运行它,它必须存在于异步任务中。

所以发生的情况是:

  • 你创建了服务器
  • 服务器从不运行,因为它没有被 await
  • 你查询服务器以获取响应
  • 响应永远不会到来,因为服务器没有运行,所以你卡在 reqwest::get

你应该做的是:

  • 启动服务器。

另外:

  • 你不需要传播服务器对象以停止它。在将其移入任务之前,你可以首先创建一个 .handle()。服务器句柄不包含对服务器的引用,而是基于智能指针。
  • 绝对不要在异步任务中使用同步通道。它将阻塞运行时,导致死锁。 (在第二个示例中它能工作的唯一原因是它很可能是多线程运行时,你只是死锁了一个运行时核心。仍然不好。)
  • (也许)如果你使用 #[actix_web::main],就不要使用 tokio::spawnactix-web 有自己的运行时,你需要使用 actix_web::rt::spawn。如果要使用基于 tokio 的任务,需要使用 #[tokio::main]actix-web 与 tokio 运行时兼容。 (EDIT: 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;
}
英文:

There are a couple of things wrong with your code; the biggest one being that you never .await the run() method.

For that fact alone you cannot run it in a normal thread, it has to exist in an async task.

So what happens is:

  • you create the server
  • the server never runs because it doesn't get awaited
  • you query the server for a response
  • the response never comes because the server doesn't run, so you get stuck in reqwest::get

What you should do instead:

  • start the server.

Also:

  • You don't need to propagate the server object out to stop it. You can create a .handle() first before you move it into the task. The server handle does not contain a reference to the server, it's based on smart pointers instead.
  • NEVER use synchronous channels with async tasks. It will block the runtime, dead-locking everything. (The only reason it worked in your second example is because it is most likely a multi-threaded runtime and you only dead-locked one of the runtime cores. Still bad.)
  • (Maybe) don't tokio::spawn if you use #[actix_web::main]. actix-web has its own runtime, you need to actix_web::rt::spawn with it. If you want to use tokio based tasks, you need to do #[tokio::main]. actix-web is compatible with the tokio runtime. (EDIT: actix-web might be compatible with tokio::spawn(), I just didn't find documentation anywhere that says it is)

With all that fixed, here is a working version:

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

huangapple
  • 本文由 发表于 2023年2月8日 21:26:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/75386470.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定