如何解决“Future不能安全地在线程之间发送”的问题?

开发 前端
当在Tokio运行的异步函数中使用Actix client时,可能会发生“error: future不能安全地在线程之间发送”的错误,这在使用Tokio和Actix库时是一个常见的问题。今天,我们来看看如何解决这个问题。

Rust应用程序通常使用异步库,如Tokio和Actix。这些库为异步I/O和并行计算等提供了有力的支持。然而,不同的异步库在一起使用时,有时会出现问题。

当在Tokio运行的异步函数中使用Actix client时,可能会发生“error: future不能安全地在线程之间发送”的错误,这在使用Tokio和Actix库时是一个常见的问题。今天,我们来看看如何解决这个问题。

让我们从一个简单的代码示例开始,它只适用于Actix,不会产生任何问题:

use actix_web::{web, App, HttpResponse, HttpServer};
use awc::Client;

#[actix_rt::main]
async fn main()  {
    actix_rt::spawn(async {
        HttpServer::new(|| {
            App::new()
                .service(web::resource("/hello").route(web::get().to(ok)))
        })
            .bind("127.0.0.1:8080")?
            .run()
            .await
    });

    let client = Client::new();
    let url = "http://127.0.0.1:8080/hello";
    let ret =  client.get(url).send().await.unwrap().body().await.unwrap();
    println!("{:?}", ret);
}

async fn ok() -> HttpResponse {
    HttpResponse::Ok()
        .content_type("text/html; charset=utf-8")
        .body("OK")
}


在这段代码中,我们使用Actix创建一个HTTP服务器,并使用Actix client向它发出GET请求。一切都很顺利,但是当我们试图在Tokio运行的异步函数中使用Actix client时,问题就开始了。

当我们尝试在Tokio运行时中调用Actix client时,我们会遇到“error: future不能安全地在线程之间发送的错误。async block创建的future不是Send。类型 awc::Client 不是Send”。这是因为Actix client不是Send,这意味着它不能在线程之间安全地传递。

下面是导致此错误的示例代码:

use actix_web::{web, App, HttpResponse, HttpServer};
use awc::Client;

#[actix_rt::main]
async fn main()  {
    actix_rt::spawn(async {
        HttpServer::new(|| {
            App::new()
                .service(web::resource("/hello").route(web::get().to(ok)))
        })
            .bind("127.0.0.1:8080")?
            .run()
            .await
    });

    let r = tokio::spawn(async move {
        let client = Client::new();
        let url = "http://127.0.0.1:8080/hello";
        client.get(url).send().await.unwrap().body().await.unwrap()
    }).await.unwrap();

    println!("{:?}", r);
}

async fn ok() -> HttpResponse {
    HttpResponse::Ok()
        .content_type("text/html; charset=utf-8")
        .body("OK")
}


为了解决这个问题并使代码在Tokio中安全使用,我们可以使用来自Tokio的Oneshot机制。这种机制允许我们封装Actix client的输出,并在线程之间安全地传递它。

下面是用Oneshot用来解决这个问题的示例代码:

use actix_web::{web, App, HttpResponse, HttpServer};
use awc::Client;

#[actix_rt::main]
async fn main()  {
    actix_rt::spawn(async {
        HttpServer::new(|| {
            App::new()
                .service(web::resource("/hello").route(web::get().to(ok)))
        })
            .bind("127.0.0.1:8080")?
            .run()
            .await
    });

      let (sender, receiver) = tokio::sync::oneshot::channel();

    actix_rt::spawn(async move {
        let client = Client::new();
        let url = "http://127.0.0.1:8080/hello";
        let _ = sender.send(client.get(url).send().await.unwrap().body().await.unwrap());
    });

    let r = tokio::spawn(async move {
        receiver.await.unwrap()
    }).await.unwrap();

    println!("{:?}", r);
    std::mem::forget(runtime);
}

async fn ok() -> HttpResponse {
    HttpResponse::Ok()
        .content_type("text/html; charset=utf-8")
        .body("OK")
}
责任编辑:武晓燕 来源: coding到灯火阑珊
相关推荐

2016-05-11 14:16:20

2018-03-21 07:08:40

2022-10-12 15:15:56

数字孪生物联网

2014-06-06 14:33:29

BYOD移动安全

2022-07-04 10:11:33

云安全混合云云计算

2024-03-14 11:22:54

2019-12-13 11:30:33

云计算IT安全

2024-01-10 17:27:00

Python开发

2011-05-06 15:56:38

打印机故障

2011-08-29 10:34:00

网络安全云安全云计算

2021-09-14 09:00:00

私有云安全云架构

2019-06-17 08:00:55

multipassbash脚本

2009-07-22 13:32:24

JDBC SQL

2024-01-22 16:38:00

AI人工智能GenAI

2023-10-11 17:38:43

Linux磁盘数据

2020-06-29 15:03:34

远程工作网络安全网络攻击

2013-12-30 10:43:15

云计算移动数据云安全

2011-09-05 13:32:56

2009-12-02 13:30:30

2023-03-01 10:02:43

点赞
收藏

51CTO技术栈公众号