为啥 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的登录/注册系统、档案系统、聊天室、论坛系统和博客/民意调查/事件管理系统。

无法阻止Primefaces民意调查

Primefaces 一项民意调查“暂停”另一项民意调查

有没有办法从 Instagram 故事中检索民意调查选民名单?

防止发布没有选择的民意调查

R语言对苏格兰独立民意调查的Meta分析