asynchronous - 在 actix-web 中生成从多部分读取数据
问题描述
我用and尝试了actix-multipart 的例子。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
?
解决方案
当您拨打此电话时:
actix_web::rt::spawn(async move {
// do things...
});
spawn
返回JoinHandle
用于轮询任务的 a。当您放下该句柄(不将其绑定到任何东西)时,该任务将“分离”,即它在后台运行。
该actix
文档在这里并不是特别有用,但在后台actix
使用了tokio
运行时。一个关键问题是tokio
,生成的任务不能保证完成。执行者需要以某种方式知道它应该在那个未来执行工作。在您的第二个示例中,生成的任务永远不会被.await
编辑,也不会通过通道与任何其他任务通信。
最有可能的是,生成的任务永远不会被轮询,也不会取得任何进展。为了确保它完成,您可以(这.await
将JoinHandle
推动任务完成)或.await
其他Future
依赖于衍生任务中的工作(通常通过使用通道)。
至于您的更一般的目标,工作已经在异步执行!最有可能的,actix
大致是您在第二个示例中尝试做的事情:收到请求后,它会生成一个任务来处理请求并反复轮询它(以及其他活动请求),直到它完成,然后发送响应.
推荐阅读
- php - Laravel 中的 Symfony 进程在 Mac 上输出 pgrep 结果,但在 Linux Debian 上不输出
- javascript - 使用 = 符号将 javascript 对象拆分为普通字符串
- android - Flutter 在构建时给出 Firebase Core 错误
- python - 如何从函数中的字符串中提取整数?
- c++ - 在属性表 (.props) 中启用/禁用“整个程序优化”(/GL)
- php - 基于产品的画廊,动态标题无法正常工作
- android - 如果图像是 HTTP 格式,Imageview 将不会显示带有 piccsso 的图像
- javascript - 自动对焦表单中活动 div 内的第一个表单元素
- r - 在 paste 和 paste0 中连接特殊字符串
- c++ - 如何读取一串布尔运算并赋予其优先级?