面试题答案
一键面试设计思路
- 资源复用:
- 使用连接池来管理数据库连接等资源。例如,对于数据库连接,可以使用
sqlx
库结合tokio
实现连接池。连接池可以预先创建一定数量的连接,当异步任务需要使用数据库连接时,从连接池中获取连接,使用完毕后再归还到连接池中,而不是每次都创建新的连接。 - 对于其他类型的资源,也可以设计类似的资源池结构,通过
Arc
(原子引用计数)和Mutex
(互斥锁)或RwLock
(读写锁)来保证线程安全地访问和复用资源。
- 使用连接池来管理数据库连接等资源。例如,对于数据库连接,可以使用
- 资源释放:
- 利用
Drop
trait。当一个持有资源的结构体离开作用域时,Drop
trait 的drop
方法会被自动调用,在这个方法中释放资源。例如,对于数据库连接,在连接池中的连接结构体实现Drop
trait,当连接不再被使用且从连接池中移除时,关闭数据库连接。 - 使用
tokio::task::LocalSet
结合tokio::spawn_local
。LocalSet
可以跟踪一组本地任务,当LocalSet
被销毁时,它会等待所有任务完成。这样可以确保所有异步任务完成后,再释放相关资源,避免资源在任务仍在使用时被释放。
- 利用
- 避免死锁:
- 按照固定顺序获取锁。如果多个任务需要获取多个资源的锁,确保所有任务都按照相同的顺序获取锁。例如,如果任务可能需要获取数据库连接锁和另一个资源锁,所有任务都先获取数据库连接锁,再获取另一个资源锁,这样可以避免死锁。
- 使用超时机制。当获取锁或资源时设置超时,
tokio
提供了tokio::time::timeout
函数。如果在规定时间内未能获取到资源或锁,任务可以选择放弃操作并进行相应处理,避免无限期等待导致死锁。
Tokio相关特性
tokio::sync::Mutex
和tokio::sync::RwLock
:用于保护共享资源,确保在同一时间只有一个任务可以访问资源,防止数据竞争。Mutex
提供独占访问,RwLock
提供读 - 写锁,允许多个任务同时读,但写操作必须独占。tokio::sync::Semaphore
:信号量可以用来限制同时访问资源的任务数量。例如,在连接池场景中,可以使用信号量来控制同时使用连接的任务数,避免过多任务同时请求连接导致资源耗尽。tokio::task::LocalSet
和tokio::spawn_local
:tokio::spawn_local
用于在当前线程本地生成一个异步任务,LocalSet
用于管理这些本地任务,确保它们在被销毁前都能正确完成,从而安全地释放资源。tokio::time::timeout
:设置操作超时,防止任务因为等待资源或锁而无限期阻塞,有助于避免死锁。