我知道像这个问题一样有数百个问题,但是我很难理解如何做我想做的事情。
我想要一个接受和处理事件的http服务器。在接收/处理事件时,我希望EventManager
将更新发送到ApplicationMonitor
,以跟踪已接受/处理了多少事件。 ApplicationMonitor
还将(最终)处理诸如跟踪并发连接数之类的事情,但是在此示例中,我只希望EventManager
将Inc('event_accepted')
更新发送到我的ApplicationMonitor
。
为了有用,我需要ApplicationMonitor
才能通过/stats
路由请求返回统计信息的快照。
所以我有一个ApplicationMonitor
,它产生一个线程并在 channel 上监听传入的Stat
事件。收到Stat
事件时,它将更新统计信息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()
}
}
由于无法克隆rx
,因此必须将引用move
放入闭包中。当我这样做时,我将不再能够在线程之外访问stats
。我以为可能需要第二个 channel ,以便线程可以回传其内部信息,但这是行不通的,因为我需要另一个线程以非阻塞方式进行监听。
这是我要使用
Arc
的地方吗?如何让
stats
在线程上下文内外存在?
最佳答案
是的,这是将stats
包装在Arc
中的地方,以便可以从不同线程对其进行多个引用。但是只包装Arc
只会给您HashMap
的只读 View -如果您需要对其进行修改,则还需要将其包装在某种东西中,以确保在同一时间只能修改一件事。时间。因此,您可能最终会得到Arc<Mutex<HashMap<&'static str, i32>>>
或Arc<RwLock<HashMap<&'static str, i32>>>
。
另外,如果您只是更改值,而不添加或删除值,则可以使用Arc<HashMap<&static str, AtomicU32>>
,它允许您并行读取和修改不同的值,而无需取出整个Map
范围的锁定,但需要Atomic
与锁相比,s更容易理解和正确使用。
关于multithreading - 在Rust中的线程之间共享可变数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63102930/