我正在使用 warp web 框架和 tokio 异步运行时在 Rust 中构建一个 Rest API,问题是我的代码中有一系列操作,其中线程无法同时执行所有操作,它们需要一次执行一个时间,我该如何在 Rust 中做到这一点?
这是需要锁定的代码块:
async fn execute() {
client_dao.get_client(id);
let new_balance = calculate_new_balance();
client_dao.transaction(id, new_balance, transaction_entity);
}
我的尝试:
use std::sync::Mutex
async fn execute() {
let mutex = Mutex::new(0);
let _guard = mutex.lock().unwrap();
client_dao.get_client(id);
let new_balance = calculate_new_balance();
client_dao.transaction(id, new_balance, transaction_entity);
}
这导致我收到错误:
async function: the trait `std::marker::Send` is not implemented for `std::sync::MutexGuard<'_, Client>`
在这个链接中https://stackoverflow.com/a/67277503/12253990我看到通过使用异步运行时,我需要使用为异步制作的互斥体,所以我尝试了这个:
use tokio::sync::Mutex;
async fn execute() {
let mutex = Mutex::new(0);
let _guard = mutex.lock().await;
client_dao.get_client(id);
let new_balance = calculate_new_balance();
client_dao.transaction(id, new_balance, transaction_entity);
}
它没有给我错误,但是互斥锁不起作用,存在竞争条件错误...我使用 k6 编写了一个脚本,该脚本同时调用端点两次,传递值 50,客户端余额为 0 ,也就是说,最终的余额应该是100,但是最终的余额是50,因为线程之间互相运行......
我尝试过的另一件事:
use tokio::sync::Mutex;
use std::sync::Arc;
async fn execute() {
let mutex = Arc::new(Mutex::new(0));
let _guard = mutex.lock().await;
client_dao.get_client(id);
let new_balance = calculate_new_balance();
client_dao.transaction(id, new_balance, transaction_entity);
}
同样的事情,没有错误,但竞争条件继续发生,线程不是一次执行一个,但我该如何在 Rust 中做到这一点?
我使用存储函数解决了这个问题,我将处理和业务规则留在数据库中,因为我可以阻止其他事务选择更新的记录,直到当前事务完成,即一次只能有一个事务可以修改所选数据,这避免了竞争条件