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
来管理长期运行的连接。