当前位置:首页 > 技术文章 > 正文内容

Rust async 函数:会 “暂停” 的魔法函数,返回的是 “未来” 的承诺

zonemu1个月前 (09-04)技术文章16



async 函数:会 “暂停” 的魔法函数,返回的是 “未来” 的承诺

先从 “点咖啡” 理解什么是 async 函数

你去咖啡店点了一杯拿铁,店员说 “稍等,做好了叫你”,然后你就站在旁边刷手机 —— 这时候你没有傻等着,还能做别的事。这个 “点咖啡” 的过程,就像调用一个 async 函数:



  • 普通函数是 “点完咖啡必须站在吧台前死等,啥也干不了”,直到拿到咖啡才走(同步执行);
  • async 函数是 “点完就拿到一个‘取餐号’(Future),可以去干别的,咖啡好了再回来取”(异步执行)。



所谓async函数,就是能 “暂停工作” 的函数。它不会像普通函数那样一口气跑完,而是在遇到await关键字时 “打个盹”,把控制权交出去,让其他任务先执行。等await的事情办完了,它再从暂停的地方接着干。

啥是 Future?就是 “还没做好,但迟早给你” 的东西

当你调用async函数时,它不会立刻返回结果,而是返回一个Future(中文叫 “未来”)。这东西就像你点咖啡时拿到的取餐号 —— 它不是咖啡本身,但拿着它,你知道 “咖啡正在做,做好了会通知你”。



比如你写了个async fn make_coffee() -> String,调用它的时候不会立刻得到 “热拿铁”,而是得到一个Future对象。这个对象有两个状态:



  • 没准备好(Pending):咖啡还在做;
  • 准备好了(Ready):咖啡做好了,可以拿结果了。



就像取餐号不会自己把咖啡送过来,Future也不会自己 “跑起来”,得靠 “执行者”(Executor)来驱动 —— 比如咖啡店的厨师就是执行者,负责把 “取餐号” 对应的咖啡做出来。

暂停点(await):async 函数的 “休息站”

async函数里的await关键字,就是 “暂停点”。它像个休息站,告诉函数:“我现在要等个东西(比如网络请求、文件读取),你先暂停,让别人用用 CPU,等我完事了再叫你继续。”



举个例子:你用async函数写一个 “早晨流程”,包括 “煮咖啡” 和 “烤面包”,这两件事可以同时做:



rust

// 模拟煮咖啡(需要2秒)
async fn brew_coffee() -> String {
    println!("开始煮咖啡...");
    // 暂停2秒(实际中可能是等待咖啡机完成)
    tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
    "香喷喷的咖啡".to_string()
}

// 模拟烤面包(需要1秒)
async fn toast_bread() -> String {
    println!("开始烤面包...");
    tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
    "酥脆的面包".to_string()
}

// 早晨流程(async函数)
async fn morning_routine() {
    // 同时启动两个任务,而不是等咖啡煮完再烤面包
    let coffee_future = brew_coffee();
    let bread_future = toast_bread();

    // 等待两个任务都完成(这里的.await就是暂停点)
    let coffee = coffee_future.await;
    let bread = bread_future.await;

    println!("早餐好了:{} + {}", coffee, bread);
}



这个例子里,brew_coffee和toast_bread都是async函数,它们内部的sleep().await就是暂停点 —— 函数会在这儿 “休息”,让 CPU 去处理别的事(比如同时烤面包)。如果用普通函数,得先等 2 秒煮完咖啡,再花 1 秒烤面包,总共 3 秒;但用async/await,两件事同时做,总共只花 2 秒(等最慢的那个完成)。

为什么需要 async 函数?解决 “等不起” 的麻烦

想象你在网上买东西,付款时需要:



  1. 检查余额(调用银行 API,耗时 1 秒);
  2. 扣钱(调用支付接口,耗时 1.5 秒);
  3. 发送订单确认短信(调用短信接口,耗时 0.5 秒)。



如果用普通函数,这三件事得串行执行,总共花 3 秒,期间你的程序啥也干不了,就像 “卡住” 了一样。



但用async函数,你可以让这三个操作 “重叠” 进行:发起查余额请求后,不等结果回来就发起扣钱请求,再发起发短信请求。最后只等最久的那个操作(1.5 秒)完成就行,大大节省时间。



这就像快递员送三件货:普通函数是送完一件再取下一件;async函数是一次性把三件货的地址都输入导航,顺路依次送达,效率高多了。

给新手的 3 个实用建议

  1. 别把 async/await 当 “万能加速剂”:如果任务本身不需要 “等”(比如纯计算),用 async 函数反而会增加开销,就像买瓶矿泉水没必要用 “外卖跑腿”,自己下楼买更快。
  2. await 只能用在 async 函数里:就像 “休息站” 只能建在高速公路上,普通函数里不能用 await,强行用会报错。
  3. Future 要 “驱动” 才会跑:拿到 Future 后,如果不调用.await或者交给执行者(比如 tokio),它就永远是 “没准备好” 的状态,就像取餐号丢了,咖啡做好了也没人去拿。

两个标题

  1. async 函数:会 “暂停” 的魔法函数,返回的是 “未来” 的承诺
  2. 从点咖啡到写代码:聊聊 async 函数的 “暂停” 与 “未来”

简介

本文用 “点咖啡”“烤面包” 等生活场景,通俗解释了 async 函数的核心逻辑:它能通过 await 暂停执行,返回的 Future 就像 “取餐号”,代表 “未来会完成的任务”。结合具体案例对比同步与异步的区别,说明 async 函数如何提高程序效率,并给出新手避坑建议,帮你轻松理解这一异步编程利器。



#async 函数 #Future #暂停点 #异步编程 #await

相关文章

Vue3 中,父子组件如何传递参数?(vue父子组件传递数据方法)

在 Vue3 中,组件化开发是非常重要的特征,那么组件之间传值就是开发中常见的需求了。组件之间的传值三种方式:父传子、子传父、非父子组件传值。一、父传子( defineProps )父组件主要通过使用...

【Vue3 基础】05.组件化(组件使用vuex)

这是 Vue3 + Vite + Pinia +TS + Element-Plus 实战系列文档。最近比较忙没什么时间写文章,争取早日把这个系列完结吧~生命周期和模板引用在本章之前,我们通过响应式 a...

崩溃!3 道 React 面试必卡题,吃透稳过金九银十

凌晨三点还在对着 “React 组件为什么重复渲染” 抓耳挠腮?别慌!今天挑出 3 道让 90% 候选人卡壳的高频题,全是大厂面试官挖的 “坑”,手把手教你见招拆招,看完直接装进面试 “弹药库”!先问...

Vue基础(vue基础组件文件名符合规范的是)

Vue 是什么,它的核心特点有哪些?Vue 是一款渐进式 JavaScript 框架,它基于标准 HTML、CSS 和 JavaScript 构建,并提供了一套声明式的、组件化的编程模型,帮助开发者用...

VIM配置整理(vim配置教程)

一、基本配色set number set showcmd set incsearch set expandtab set showcmd set history=400 set autoread se...

前端学习又一大里程碑:html5+js写出歌词同步手机播放器

需要完整代码和视频请评论后加前端群470593776领取javascript进阶课题:HTML5迷你音乐播放器学习疲惫了,代码敲累了,听听自己做的的音乐播放器,放松与满足知识点:for循环语句,DOM...