我尝试了actix-多部分示例与actix-web v3.3.2和actix-multipart v0.3.0。
举个最小的例子,
use actix_multipart::Multipart;
use actix_web::{post, web, App, HttpResponse, HttpServer};
use futures::{StreamExt, TryStreamExt};
#[post("/")]
async fn save_file(mut payload: Multipart) -> HttpResponse {
while let Ok(Some(mut field)) = payload.try_next().await {
let content_type = field.content_disposition().unwrap();
let filename = content_type.get_filename().unwrap();
println!("filename = {}", filename);
while let Some(chunk) = field.next().await {
let data = chunk.unwrap();
println!("Read a chunk.");
}
println!("Done");
}
HttpResponse::Ok().finish()
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| App::new().service(save_file))
.bind("0.0.0.0:8080")?
.run()
.await
}这很好,但是我想异步地处理表单数据。所以我试了一下:
use actix_multipart::Multipart;
use actix_web::{post, web, App, HttpResponse, HttpServer};
use futures::{StreamExt, TryStreamExt};
#[post("/")]
async fn save_file(mut payload: Multipart) -> HttpResponse {
actix_web::rt::spawn(async move {
while let Ok(Some(mut field)) = payload.try_next().await {
let content_type = field.content_disposition().unwrap();
let filename = content_type.get_filename().unwrap();
println!("filename = {}", filename);
while let Some(chunk) = field.next().await {
let data = chunk.unwrap();
println!("Read a chunk.");
}
println!("Done");
}
});
HttpResponse::Ok().finish()
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| App::new().service(save_file))
.bind("0.0.0.0:8080")?
.run()
.await
}(将actix_web::rt::spawn添加到save_file.)
但这是行不通的-- "Done"从未打印过的信息。第二种情况下显示的"Read a chunk"数量少于第一种情况,因此我猜在读取所有数据之前,field.next().await不可能因为某种原因而终止。
我对异步编程不太了解,所以我不知道为什么field.next()没有在actix_web::rt::spawn中工作。
我的问题是:为什么是这样,我如何处理actix_web::rt::spawn?
发布于 2021-02-13 02:50:04
当你打这个电话时:
actix_web::rt::spawn(async move {
// do things...
});spawn返回用于轮询任务的JoinHandle。当您删除该句柄(通过不将其绑定到任何东西)时,任务将被“分离”,也就是说,它在后台运行。
actix文档在这里并不特别有用,但是actix在幕后使用tokio运行时。一个关键的问题是,在tokio中,生成的任务不能保证完成。执行者需要知道,不知何故,它应该为这个未来工作。在第二个示例中,生成的任务从未被.await编辑过,也没有通过通道与任何其他任务进行通信。
最有可能的是,生成的任务永远不会被轮询,也不会取得任何进展。为了确保它完成,您可以使用.await JoinHandle (它将驱动任务完成)或.await其他一些依赖于生成任务中的工作的Future (通常通过使用一个通道)。
至于您更普遍的目标,工作已经异步执行了!最有可能的是,actix正在执行您在第二个示例中试图做的工作:在接收到请求时,它会产生一个任务来处理请求,并反复轮询它(以及其他活动请求),直到它完成,然后发送一个响应。
https://stackoverflow.com/questions/66169240
复制相似问题