所有权/借用/生命周期
解释下所有权模型
所有权模型是为了解决在无GC的前提下,进行内存管理并保证内存安全。
其核心规则有3个:
每个值同一时间有且只有一个所有者
当值超出作用域内存即被释放
当所有权转移后,原先的变量就失效了
其本质是通过在编译阶段杜绝空指针和悬垂指针等内存问题。
所有权模型 = 编译期严格的内存管理规则 + 自动内存释放 + 零运行时开销
解释下生命周期
生命周期是通过约束引用与数据之间的关系,保证引用的数据始终可用,从而解决悬垂引用的问题,
核心规则:引用生命周期 ≤ 数据生命周期
Trait / 泛型 / 零成本抽象
解释下零成本抽象
零成本抽象就是在使用高级语言特性的时候,无需额外开销。
在rust中零成本抽象的例子有Trait、迭代器、泛型、内联、宏等。
它本质上是在编译期阶段将高级语言代码转成机器代码,从而实现与底层代码一样的性能。
具体实现依赖于:
编译期单态化,如泛型,在编译阶段直接生成各个类型的独立代码,不需要分发开销
编译期展开,如迭代器,在编译阶段将链式调用展开成高效循环
零成本抽象 = 高级语法 + 编译期优化 = 零运行时开销 = 底层级性能
异步编程
async和await的底层原理
通过async将一个函数标记为异步函数,返回一个Future,本质上是一个状态机,它需要一个runtime来进行调用。通常我们会调用tokio这类第三方库来创建一个runtime,await会将这个状态机挂起,然后将其交给runtime的executor,executor通过poll机制来进行调度执行。
协程无栈:不保存完整调用栈,内存占用极小
无线程开销:不绑定线程,完全在用户态协程运行
零成本异步:无虚拟机,无GC,无调度切换
async/await = 编译期生成状态机 + 运行时 poll 驱动 + 用户态无栈协程 = 零成本、高并发、异步 IO
并发编程
rust如何避免数据竞争
rust通过Send来进行跨线程间的所有权传递,通过Sync来进行跨线程的数据共享访问,同一时间只允许有一个可变引用或多个不可变引用,在编译阶段检查约束。
Rust 通过「所有权 / 借用规则 + Send + Sync」,在编译期强制约束:要么单线程独占,要么多线程只读,要么用安全锁保护;从根源杜绝数据竞争,运行时绝对安全。
性能调优
在实际项目中,如何进行性能调优?
代码层
避免锁竞争,如读多写少的使用Arc<RwLock<T>>,读少写多的使用Arc<Mutex<T>>,高频访问数据使用Atomic<T>,使用消息队列channel代替共享内存
减少内存分配,预分配内存,少用clone
使用并发,异步函数里不要写调同步操作,CPU密集型任务使用线程池
编译层
使用cargo --release启用llvm优化
监控层
使用prometheus+grafana观测响应时间、CPU和内存占用情况
分析层
使用perf分析CPU使用
使用jemalloc分析跟踪内存使用
使用flamegraph绘制火焰图