Hi, I have the following code to simulate a data server behavior:
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
#[derive(Debug)]
struct OneServer(u32);
#[derive(Default, Debug)]
struct Servers {
servers: Vec<Rc<RefCell<OneServer>>>,
}
impl Servers {
fn push_data(&self, _data: Vec<u8>) {
for s in self.servers.iter() {
let mut s = s.borrow_mut();
s.0 += 1;
}
}
fn add_server(&mut self, server: Rc<RefCell<OneServer>>) {
self.servers.push(server)
}
}
struct Dispatcher {
servers: HashMap<String, Rc<RefCell<Servers>>>,
}
impl Dispatcher {
fn new() -> Self {
Self {
servers: HashMap::default(),
}
}
fn register(&self, inst_type: &str, server: Rc<RefCell<OneServer>>) {
println!("register: debug servers: {:?}", self.servers);
let mut servers = self.servers.get(inst_type).unwrap().borrow_mut();
servers.add_server(server)
}
fn push_data(&self, inst_type: &str, data: Vec<u8>) {
println!("push_tick: debug servers: {:?}", self.servers);
let servers = self.servers.get(inst_type).unwrap().borrow_mut();
servers.push_data(data)
}
}
fn main() {
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build_local(&mut Default::default())
.unwrap();
runtime.block_on(async {
let mut dispatcher = Dispatcher::new();
dispatcher.servers.insert(
"stock".to_string(),
Rc::new(RefCell::new(Servers::default())),
);
let dispatcher = Rc::new(dispatcher);
let dispatcher_clone = dispatcher.clone();
// worker 1.
runtime.spawn_local(async move {
loop {
tokio::time::sleep(std::time::Duration::from_millis(500)).await;
dispatcher_clone.push_data("stock", vec![]);
println!("call push tick complete.")
}
});
// worker 2.
loop {
let dispatcher_clone = dispatcher.clone();
tokio::time::sleep(std::time::Duration::from_millis(500)).await;
runtime.spawn_local(async move {
let server = Rc::new(RefCell::new(OneServer(0)));
dispatcher_clone.register("stock", server);
println!("call register complete.");
});
}
});
}
The core idea is I have a HashMap<String, Rc<RefCell<Servers>>>
, which will call register
to add a server to Servers
in worker 2
. In worker 1
, data will be push to servers
periodically.
I chose tokio's LocalRuntime is because I don't want to use lock, the data will be updated really fast, locking will likely to cause performance issues. But I have to use Rc<RefCell<servers>>
and Rc<RefCell<OneServer>>
to gain internal mutability, not really sure is there a better way to achieve this? Nested Rc<RefCell<T>>
seems not good to me.
Here is the repo for the code: GitHub - WindSoilder/tmp_aaa