最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

invoke async code in sync function blocked in rust - Stack Overflow

programmeradmin8浏览0评论

I want to invoke a http rpc in rust, but current context is sync. Then I tried like this to invoke the remote rpc:

 let uniq_id = executor::block_on(get_snowflake_id());

and this is the get_snowflake_id function:

use std::env;
use log::error;
use reqwest::Client;
use rust_wheel::model::response::api_response::ApiResponse;

pub async fn get_snowflake_id() -> Option<i64> {
    let client = Client::new();
    let infra_url = env::var("INFRA_URL").expect("INFRA_URL must be set");
    let url = format!("{}{}", infra_url, "/infra-inner/util/uniqid/gen");
    let resp = client
        .get(format!("{}", url))
        .body("{}")
        .send()
        .await;
    if let Err(e) = resp {
        error!("get id failed: {}", e);
        return None;
    }
    let text_response = resp.unwrap().text().await;
    if let Err(e) = text_response {
        error!("extract text failed: {}", e);
        return None;
    }
    let resp_str = text_response.unwrap_or_default();
    let resp_result = serde_json::from_str::<ApiResponse<i64>>(&resp_str);
    if let Err(pe) = resp_result {
        error!("parse failed: {}, response: {}", pe, &resp_str);
        return None;
    }
    Some(resp_result.unwrap().result)
}

but this code is blocked forever, am I doing the right way to invoke async code in sync context? I have to do like this because the context is sync, I can not change the current context invoke style to async. I have tried:

pub fn get_uniq_id() -> Option<i64> {
    task::block_in_place(|| {
        tokio::runtime::Handle::current().block_on(get_snowflake_id())
    })
}

shows error can call blocking only when running on the multi-threaded runtime. This is the application entry:

#[actix_web::main]
async fn main() -> std::io::Result<()> {}

I want to invoke a http rpc in rust, but current context is sync. Then I tried like this to invoke the remote rpc:

 let uniq_id = executor::block_on(get_snowflake_id());

and this is the get_snowflake_id function:

use std::env;
use log::error;
use reqwest::Client;
use rust_wheel::model::response::api_response::ApiResponse;

pub async fn get_snowflake_id() -> Option<i64> {
    let client = Client::new();
    let infra_url = env::var("INFRA_URL").expect("INFRA_URL must be set");
    let url = format!("{}{}", infra_url, "/infra-inner/util/uniqid/gen");
    let resp = client
        .get(format!("{}", url))
        .body("{}")
        .send()
        .await;
    if let Err(e) = resp {
        error!("get id failed: {}", e);
        return None;
    }
    let text_response = resp.unwrap().text().await;
    if let Err(e) = text_response {
        error!("extract text failed: {}", e);
        return None;
    }
    let resp_str = text_response.unwrap_or_default();
    let resp_result = serde_json::from_str::<ApiResponse<i64>>(&resp_str);
    if let Err(pe) = resp_result {
        error!("parse failed: {}, response: {}", pe, &resp_str);
        return None;
    }
    Some(resp_result.unwrap().result)
}

but this code is blocked forever, am I doing the right way to invoke async code in sync context? I have to do like this because the context is sync, I can not change the current context invoke style to async. I have tried:

pub fn get_uniq_id() -> Option<i64> {
    task::block_in_place(|| {
        tokio::runtime::Handle::current().block_on(get_snowflake_id())
    })
}

shows error can call blocking only when running on the multi-threaded runtime. This is the application entry:

#[actix_web::main]
async fn main() -> std::io::Result<()> {}
Share Improve this question edited Mar 23 at 9:32 Dolphin asked Mar 23 at 7:02 DolphinDolphin 39.3k102 gold badges376 silver badges717 bronze badges 6
  • 1 I suspect that you'll have to use a tokio runtime instead of executor::block_on since reqwest depends on some tokio stuff. – cdhowie Commented Mar 23 at 7:23
  • tokio runtime need multi thread to do this, I did not know how to turn on the multithread. – Dolphin Commented Mar 24 at 2:01
  • Tokio's runtime does not actually require multiple threads. I'm not sure where you read that. – cdhowie Commented Mar 24 at 4:45
  • I am not read that, I changed and the application shows that need multiple threads. – Dolphin Commented Mar 24 at 6:22
  • The default Tokio runtime configuration uses multiple threads, but you can configure it to run only on the thread from which the runtime was launched. – cdhowie Commented Mar 24 at 6:31
 |  Show 1 more comment

1 Answer 1

Reset to default 1

If your application ready uses Tokio, you should use a dedicated blocking call provided by Tokio:

use tokio::runtime::Runtime;

fn invoke_sync() -> Option<i64> {
    let rt = Runtime::new().unwrap();
    rt.block_on(get_snowflake_id())
}
use tokio::runtime::Runtime;
use once_cell::sync::Lazy;

static TOKIO_RT: Lazy<Runtime> = Lazy::new(|| {
    Runtime::new().expect("Failed to create Tokio runtime")
});

fn invoke_sync() -> Option<i64> {
    TOKIO_RT.block_on(get_snowflake_id())
}

If your application running inside a Tokio runtime, you should use Tokio's dedicated blocking mechanism:

use tokio::task;

fn invoke_sync() -> Option<i64> {
    task::block_in_place(|| {
        // This is safe if you're already within a Tokio runtime
        tokio::runtime::Handle::current().block_on(get_snowflake_id())
    })
}

Use tokio::task::block_in_place + Handle::current().block_on(...)

Outside Tokio runtime (pure sync):

Create and reuse a global runtime (tokio::runtime::Runtime) and call .block_on(...).

FYI:Docs-Tokio

发布评论

评论列表(0)

  1. 暂无评论