[英]Sharing Mutable Data Between Threads in Rust
I know there are hundreds of questions just like this one, but i'm having trouble wrapping my head around how to do the thing I'm trying to do.我知道有数百个像这个问题一样的问题,但我无法解决如何做我想做的事情。
I want an http server that accepts and processes events.我想要一个接受和处理事件的 http 服务器。 On receiving/processing an event, i want the
EventManager
to send an update to an ApplicationMonitor
that is tracking how many events have been accepted/processed.在接收/处理事件时,我希望
EventManager
向ApplicationMonitor
发送更新,以跟踪已接受/处理了多少事件。 The ApplicationMonitor
would also (eventually) handle things like tracking number of concurrent connections, but in this example I just want my EventManager
to send an Inc('event_accepted')
update to my ApplicationMonitor
. ApplicationMonitor
还将(最终)处理诸如跟踪并发连接数之类的事情,但在此示例中,我只希望我的EventManager
向我的ApplicationMonitor
发送Inc('event_accepted')
更新。
To be useful, I need the ApplicationMonitor
to be able to return a snapshot of the stats when the requested through a /stats
route.为了有用,我需要
ApplicationMonitor
能够在通过/stats
路由请求时返回统计信息的快照。
So I have an ApplicationMonitor
which spawns a thread and listens on a channel for incoming Stat
events.所以我有一个
ApplicationMonitor
,它产生一个线程并在通道上监听传入的Stat
事件。 When it receives a Stat
event it updates the stats HashMap.当它接收到一个
Stat
事件时,它会更新统计数据 HashMap。 The stats hashmap must be mutable within both ApplicationMonitor
as well as the spawned thread.统计信息 hashmap 在
ApplicationMonitor
和衍生线程中必须是可变的。
use std::sync::mpsc;
use std::sync::mpsc::Sender;
use std::thread;
use std::thread::JoinHandle;
use std::collections::HashMap;
pub enum Stat {
Inc(&'static str),
Dec(&'static str),
Set(&'static str, i32)
}
pub struct ApplicationMonitor {
pub tx: Sender<Stat>,
pub join_handle: JoinHandle<()>
}
impl ApplicationMonitor {
pub fn new() -> ApplicationMonitor {
let (tx, rx) = mpsc::channel::<Stat>();
let mut stats: HashMap<&'static str, i32> = HashMap::new();
let join_handle = thread::spawn(move || {
for stat in rx.recv() {
match stat {
Stat::Inc(nm) => {
let current_val = stats.entry(nm).or_insert(0);
stats.insert(nm, *current_val + 1);
},
Stat::Dec(nm) => {
let current_val = stats.entry(nm).or_insert(0);
stats.insert(nm, *current_val - 1);
},
Stat::Set(nm, val) => {
stats.insert(nm, val);
}
}
}
});
let am = ApplicationMonitor {
tx,
join_handle
};
am
}
pub fn get_snapshot(&self) -> HashMap<&'static str, i32> {
self.stats.clone()
}
}
Because rx
cannot be cloned, I must move
the references into the closure.因为
rx
不能被克隆,我必须move
引用移动到闭包中。 When I do this, I am no longer able to access stats
outside of the thread.当我这样做时,我不再能够访问线程之外的
stats
。
I thought maybe I needed a second channel so the thread could communicate it's internals back out, but this doesn't work as i would need another thread to listen for that in a non-blocking way.我想也许我需要第二个通道,以便线程可以将其内部通信传回,但这不起作用,因为我需要另一个线程以非阻塞方式监听它。
Is this where I'd use Arc
?这是我使用
Arc
的地方吗?
How can I have stats
live inside and out of the thread context?如何让
stats
在线程上下文内外存在?
Yes, this is a place where you'd wrap your stats
in an Arc
so that you can have multiple references to it from different threads.是的,这是您将
stats
包装在Arc
中的地方,这样您就可以从不同的线程中对它进行多次引用。 But just wrapping in an Arc
will only give you a read-only view of the HashMap
- if you need to be able to modify it, you'll also need to wrap it in something which guarantees that only one thing can modify it at a time.但是仅仅包裹在
Arc
中只会给你一个HashMap
的只读视图——如果你需要能够修改它,你还需要把它包裹在一个保证只有一个东西可以修改它的东西中时间。 So you'll probably end up with either an Arc<Mutex<HashMap<&'static str, i32>>>
or a Arc<RwLock<HashMap<&'static str, i32>>>
.因此,您最终可能会得到
Arc<Mutex<HashMap<&'static str, i32>>>
或Arc<RwLock<HashMap<&'static str, i32>>>
。
Alternatively, if you're just changing the values, and not adding or removing values, you could potentially use an Arc<HashMap<&static str, AtomicU32>>
, which would allow you to read and modify different values in parallel without needing to take out a Map
-wide lock, but Atomic
s can be a little more fiddly to understand and use correctly than locks.或者,如果您只是更改值,而不是添加或删除值,您可能会使用
Arc<HashMap<&static str, AtomicU32>>
,这将允许您并行读取和修改不同的值而无需采取出一个Map
范围的锁,但是Atomic
比锁更容易理解和正确使用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.