tokio::spawn(async move {
if let Err(err) = conn.await {
let err_msg = format!("Connection failed: {:?}", err);
dbg!(err_msg);
}
});
为什么不能是
if let Err(err) = conn.await {
let err_msg = format!("Connection failed: {:?}", err);
dbg!(err_msg);
}
这是一个很好的问题!这里必须使用tokio::spawn
的原因是:
-
并发处理:
conn
代表的是与远程服务器的连接,它需要持续运行来处理数据传输。如果直接conn.await
,会阻塞当前函数直到连接关闭。这意味着:- 在连接关闭之前,后续的代码无法执行
- 无法同时处理多个请求
-
背景任务:通过将
conn
放在tokio::spawn
中,我们将连接处理转移到后台任务,这样:- 主流程可以继续处理新的请求
- 连接可以在后台独立运行
- 即使连接出错,也不会影响主要的请求处理流程
举个例子来说明:
// 错误方式:
async fn handle() {
let (sender, conn) = https_remote_connect().await?;
conn.await?; // 这里会阻塞,直到连接关闭!
// 下面的代码要等到连接关闭才能执行
process_requests(sender); // 永远无法到达这里
}
// 正确方式:
async fn handle() {
let (sender, conn) = https_remote_connect().await?;
tokio::spawn(async move {
if let Err(err) = conn.await {
// 处理错误...
}
});
// 立即执行,不需要等待连接关闭
process_requests(sender); // 可以立即处理请求
}
这就是为什么在异步网络编程中,我们经常需要使用tokio::spawn
来管理长期运行的连接。