An object pool
I have a struct that is expensive to init and it cannot be shared between threads (it's a third party lib so I can't change it).
However, I need to use it in a multi-threaded high-throughput environment - it has to be used by an Axum service serving multiple concurrent requests.
That leaves me with few choices:
- Share it in Mutex - not a good possibility because the bottleneck might be too much
- Initialize a copy for each request - also not good because its too expensive to create
- keep a shared pool of these structs that I can use for each request.
I have tried to implement the latter and wonder if this makes sense. The general idea is to keep a vector of mutexes wrapping my struct, and then when a req arrives try to access a random mutex there, hoping that most of the time different mutexes will be accessed and therefore will be available to lock .
struct State {
locked_objs: Vec<Mutex<Obj>>,
}
impl State {
async fn get_model_instance(&self) -> MutexGuard<'_, Obj> {
let objs_len = self.locked_models.len();
let random_index = rand::random::<usize>() % objs_len;
self.locked_objs[random_index].lock().await
}
}
would be happy for feedback
UPDATE:after some great suggestions, it seems that using thread\_local is the most elegant, though using with once\_cell got me into troubles with lifetimes so implemented it like this
thread_local! {
static LOCAL_MODEL: Arc<SequenceClassificationModel> = Arc::new(init_sequence_classifier());
}
fn get_model_instance() -> Arc<SequenceClassificationModel> {
LOCAL_MODEL.with(|model| model.clone())
}
The other better solution is to iterate all mutexs first and try with try\_lock
loop {
for model in &self.locked_models {
match model.try_lock() {
Ok(guard) => return guard,
Err(_) => continue,
}
}
}
}