为啥 Mio 的民意调查会针对用户生成的事件触发两次?
Posted
技术标签:
【中文标题】为啥 Mio 的民意调查会针对用户生成的事件触发两次?【英文标题】:Why is Mio's poll triggered twice for user-generated events?为什么 Mio 的民意调查会针对用户生成的事件触发两次? 【发布时间】:2018-05-03 06:02:06 【问题描述】:以下代码生成一个“用户事件”,由poll
返回:
extern crate mio;
use mio::event::Evented;
use mio::Events, Poll, PollOpt, Ready, Registration, Token;
use std::thread::sleep, spawn, JoinHandle;
use std::time::Duration, Instant;
#[derive(Debug)]
struct Output(u32, Duration);
pub struct MioThread
registration: Registration,
handle: JoinHandle<Output>,
impl MioThread
pub fn new(i: u32) -> MioThread
let now = Instant::now();
let (registration, set_readiness) = Registration::new2();
let handle = spawn(move ||
sleep(Duration::from_millis((1000 - (100 * i)) as u64));
set_readiness.set_readiness(Ready::readable()).unwrap();
Output(i, now.elapsed())
);
MioThread
registration: registration,
handle: handle,
// manage the thread result
fn eval_result(self)
let out = self.handle.join();
println!("do whathever you want with: :?", out.unwrap());
fn main()
let poll = Poll::new().unwrap();
let mut events = Events::with_capacity(16);
let mut tasks = Vec::new();
for i in 0..5
let mio_thread = MioThread::new(i);
mio_thread
.registration
.register(&poll, Token(i as usize), Ready::readable(), PollOpt::edge())
.unwrap();
tasks.push(Some(mio_thread));
loop
let num_events = poll.poll(&mut events, None).unwrap();
println!("poll fired: events", num_events);
for event in &events
if event.readiness().is_readable()
let Token(thread_id) = event.token();
if let Some(t) = tasks.remove(thread_id)
t.eval_result();
输出是:
poll fired: 1 events
do whathever you want with: Output(4, Duration secs: 0, nanos: 600967623 )
poll fired: 0 events
poll fired: 1 events
do whathever you want with: Output(3, Duration secs: 0, nanos: 701035026 )
poll fired: 0 events
poll fired: 1 events
do whathever you want with: Output(2, Duration secs: 0, nanos: 801089370 )
poll fired: 0 events
poll fired: 1 events
do whathever you want with: Output(1, Duration secs: 0, nanos: 900890190 )
poll fired: 0 events
poll fired: 1 events
do whathever you want with: Output(0, Duration secs: 1, nanos: 600076 )
poll fired: 0 events
我打开了an issue on the Mio repository。
【问题讨论】:
我没有看到任何额外的事件。对poll
的第一次调用按预期阻塞,所有后续备用调用也是如此。但是中间的调用会立即返回(没有事件)。我不知道为什么会这样,但我也不明白为什么会出现问题......
如果您不从tasks
Vec 中删除已完成的任务,它实际上不会发生。猜测一下,我会说Registration::drop
正在更新Poll
的状态,导致poll
由于状态更改而返回,即使没有新事件。
你是对的,一般来说这不是问题。但是在某些特定情况下,您希望尽可能优化事件循环线程,或者像我的情况一样,要了解 Mio 的工作原理,可能我遗漏了一些东西。
【参考方案1】:
如cmets中所述并确认here:
删除注册可能会唤醒循环(确实如此,与注册相同)而不会实际触发事件
这在大多数情况下显然不是问题,只是我在阅读docs后没想到的行为:
fn poll(&self, events: &mut Events, timeout: Option) -> 结果[−] 等待就绪事件
阻塞当前线程并等待已向此 Poll 实例注册的任何 Evented 句柄的就绪事件。该函数将阻塞,直到至少接收到一个就绪事件或超时已过。 None 的超时意味着轮询将阻塞,直到收到就绪事件。
删除Registration
时,当前线程确实也被唤醒了。
【讨论】:
以上是关于为啥 Mio 的民意调查会针对用户生成的事件触发两次?的主要内容,如果未能解决你的问题,请参考以下文章
完整的基于PHP的登录/注册系统、档案系统、聊天室、论坛系统和博客/民意调查/事件管理系统。