多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Rust 异步编程与 Tokio 运行时:代码评审该盯住哪些细节

Rust 异步编程与 Tokio 运行时:代码评审该盯住哪些细节 Rust 异步编程与 Tokio 运行时代码评审该盯住哪些细节异步代码评审时我先找阻塞调用。把文件读取或长计算塞进 async 函数可能让运行时线程停住。let body tokio::task::spawn_blocking(|| std::fs::read_to_string(demo.txt)).await??;还要确认任务句柄是否被等待、channel 关闭时循环会不会退出、超时后资源会不会继续运行。评审样例用临时文件日志里不要把读取内容打印出来。没有压测数据时不对性能下判断。先把运行时线程和业务线程分开看async不是“自动变快”的标记。它的作用是让任务在等待 I/O 时把执行权交回运行时如果函数里仍然做同步文件访问、压缩、解析大文本或持锁计算当前 worker 还是会被占住。代码评审里不必看到同步调用就机械地改成spawn_blocking先问清楚这段工作量和调用频率一次很短的计算可能不值得切线程持续时间不可控的工作则不应留在异步任务里。把工作挪到 blocking 线程池后也要看调用处是否会无节制地创建任务。一个请求启动一个大计算表面上没有阻塞 Tokio worker实际上可能把机器的 CPU、磁盘或线程池排满。更稳妥的写法是把并发入口限制在业务边界例如由队列、信号量或批处理策略控制而不是让每层函数都自行spawn。评审意见应指出限制放在哪里、超出限制后请求如何处理而不是只留下“注意并发”四个字。任务的生命周期要能被追到检查JoinHandle时我会先区分两种意图。确实需要结果的任务必须await否则失败只会留在后台只为发送通知的任务也应明确说明它可以独立结束并在需要时保留取消通道。丢弃句柄不等于取消任务很多人会在超时分支里误以为离开作用域就已经停掉了后台工作。若任务持有连接、文件或较大的缓存这个误解会变成难查的资源占用。超时通常只覆盖“等待结果”这一步未必会停止被等待的操作。因此评审时要沿着调用链找取消点超时以后谁通知下游接收方在哪个等待点检查通知清理逻辑是否一定执行。对于无法中断的阻塞调用至少要让它不再持有请求上下文也不要继续向已关闭的响应通道发送结果。这样即使它晚些结束也不会把过期结果写回当前请求。channel 的关闭路径不能只靠 happy path生产代码里常见的接收循环看起来很简洁却在发送端全部释放后继续空转。评审时应确认recv的返回值被正确处理关闭被视为正常结束还是异常要和业务语义一致。多生产者场景还要看是否有一个长期存活的 sender 把 channel 意外保住导致消费者永远等不到关闭。错误处理同样要保留上下文。把 Tokio 的 join 错误、I/O 错误一律转成字符串会让上层无法判断是可以重试的临时失败还是代码 panic、权限不足等需要立即暴露的问题。可以在边界处统一成应用错误类型但不要抹掉原始错误来源日志只记录定位所需的路径、操作类型和关联标识读取到的内容仍然不应进入日志。用小场景验证评审结论这类改动不需要先做大规模压测。可以用临时目录验证文件读取和清理用一个故意不发送消息的 sender 验证等待与关闭用一个可控的慢任务验证超时后是否还会写结果。测试结束时再检查任务是否退出、临时资源是否释放。若确实要讨论吞吐或延迟应把测试环境、负载形态和观测指标写出来没有这些前提性能判断很容易变成猜测。
返回列表