在返回响应后在后台运行长时间异步函数

3
在我的 actix-web 处理程序中,我想调用一个在后台运行并立即向用户返回响应的函数:
async fn heavy_computation() -> {
    // do some long running computation
}

async fn index(req: HttpRequest) -> impl Responder {
    // start computation
    heavy_computation(); 
    
    // render and return template
    let out context = Context::new();
    context.insert("foo", "bar");
    render_template("my_template.html", &context)

    // computation finishes
}

#[actix_rt::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new()
            .service(web::resource("/").route(web::get().to(index)))
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

如果我使用await来等待未来结果,那么响应直到计算完成后才会返回;如果我不使用await,函数根本不会执行。


如果你想的话,你可以理想地编写一个Actor并使用do_send方法。https://docs.rs/actix/0.10.0-alpha.3/actix/struct.Addr.html#method.do_send 如果这是你想要的答案,我可以为你写一篇。 - Njuguna Mureithi
1个回答

2
假设您正在使用 tokio 作为异步运行时,您可以使用 tokio::task::spawn 生成两个任务,然后使用 tokio::join 将它们合并:
use tokio::task;
use tokio::time;
use std::time::Duration;

async fn heavy_computation() {
    time::delay_for(Duration::from_millis(2000)).await;
    println!("heavy computation finished");
}

async fn light_computation() {
    time::delay_for(Duration::from_millis(500)).await;
    println!("light computation finished");
}

#[tokio::main]
async fn main() {
    let heavy = task::spawn(heavy_computation());
    println!("computation started");
    let light = task::spawn(async move {
        for _ in 0..3 {
            light_computation().await;
        }
    });
    let (a, b) = tokio::join!(heavy, light);
    // use the results so the compiler doesn't complain
    a.unwrap();
    b.unwrap();
}

转到游乐场


我认为这个代码并不符合我的要求,如果我正确理解了你的代码。我已经在我的问题中更新了更多细节和一个更加恰当的示例来说明我的需求。 - Oskar Persson
@OskarPersson 我认为它指出了正确的方向。您可以在索引函数中生成一个tokio任务来执行繁重的计算。 - Brendan Wilson
这帮助我使用Rocket实现了OP最初想要使用Actix实现的功能。生成的async move块在响应被刷新到客户端后继续工作。 - marekful

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接