V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
SuperFashi
V2EX  ›  问与答

有无效率高的方法检测状态的变更

  •  
  •   SuperFashi · 2016-08-18 19:50:20 +08:00 · 2193 次点击
    这是一个创建于 3030 天前的主题,其中的信息可能已经有所发展或是发生改变。

    假如有一个参数,只能读取,检测这个参数变化的方法只有无限地获取参数数据并和上一次对比吗?

    如果没有的话,假设这个参数就是一个按钮的状态, 0 或 1 的值。如果把两次检测的时间设的短的话,会很耗 CPU 资源;如果设的长的话有可能延迟明显,而且甚至有可能检测不到状态变更,有什么好的经验或者办法吗?

    17 条回复    2016-08-18 23:34:00 +08:00
    cxe2v
        1
    cxe2v  
       2016-08-18 20:01:51 +08:00
    难道不可以在状态变更的时候通知一下观察者吗?
    《观察者模式》?《订阅模式》
    htfy96
        2
    htfy96  
       2016-08-18 20:23:02 +08:00 via Android
    给具体情景
    SuperFashi
        3
    SuperFashi  
    OP
       2016-08-18 21:08:50 +08:00
    @cxe2v 无,一个参数,只能读取,其本身是无法进行任何行动的。

    @htfy96 就比如有个按钮啊,但是这个按钮只能读取其状态,但其状态改变时无法通知回来。
    cxe2v
        4
    cxe2v  
       2016-08-18 21:11:36 +08:00
    @SuperFashi 参数你可以有访问器啊,类似 java 和 c#里都会有这个东西,访问器里就可以在属性变化的时候进行一些操作
    oott123
        5
    oott123  
       2016-08-18 21:12:16 +08:00

    基本没有

    在某些场景下可以尝试慢慢增加读取间隔,一旦获取到变更之后又缩短。
    lecher
        6
    lecher  
       2016-08-18 21:13:09 +08:00
    换个思路,给这个参数的值变更加个方法, setValue 之类的,再写一个 bindEvent 专门用来传入需要绑定的事件,然后在 setValue 这个方法被调用的时候去调用 bindEvent 里面传入的事件,达到唤醒对应的绑定事件的目的。
    这个方式是主动触发绑定事件的。效率和实时性都可以满足要求。
    SuperFashi
        7
    SuperFashi  
    OP
       2016-08-18 21:39:48 +08:00
    @lecher @cxe2v 额,条件还要再苛刻点,假设那个值就是一个物理的值,比如一个物理按钮的开关的状态,获取时就是获取目前开关电势差,这样如何?
    xmoiduts
        8
    xmoiduts  
       2016-08-18 21:47:18 +08:00 via Android
    @SuperFashi 我觉得这个例子不恰当,因为物理值可以配置中断,整个过程和 cpu 无关。
    htfy96
        9
    htfy96  
       2016-08-18 21:54:43 +08:00
    @SuperFashi 一般硬件都有触发中断的机制。即使是按钮的话除了轮询之外一般都有办法让触发的时候调用某个方法如#6 。

    很多时候并不是真的只能读取。页面上除非在做什么第三方插件之类的东西(即使是大多数情况下也可以强行绑定,只是手段比较黑而已),一般都可以的。

    检测变化要么主动去读(轮询),要么被动等唤醒(中断),要么混合两者
    SuperFashi
        10
    SuperFashi  
    OP
       2016-08-18 22:27:31 +08:00
    @xmoiduts @htfy96 那太底层了,目前还没有这个技术,有什么好的教程吗?
    htfy96
        11
    htfy96  
       2016-08-18 22:31:45 +08:00
    @SuperFashi 给具体情景。如果是硬件给型号、接口;软件要有具体描述
    SuperFashi
        12
    SuperFashi  
    OP
       2016-08-18 22:35:50 +08:00   ❤️ 1
    @htfy96 标准 GPIO 接口,再详细一点就是 RPi 上的
    htfy96
        13
    htfy96  
       2016-08-18 22:45:53 +08:00 via Android
    @SuperFashi so 就有一贴 GPIO Events in Python ,可以事件驱动,注册一个回调函数的
    htfy96
        14
    htfy96  
       2016-08-18 22:51:10 +08:00 via Android
    @SuperFashi 看了一下内部实现是另开了个线程 然后基于 epoll 实现的事件循环
    SuperFashi
        15
    SuperFashi  
    OP
       2016-08-18 23:05:12 +08:00
    @htfy96 所以其实还是个循环吗,只不过是个系统级的?我也看了下实现,根本看不懂……
    htfy96
        16
    htfy96  
       2016-08-18 23:33:22 +08:00 via Android
    @SuperFashi 首先注册 epoll 的时候,内部相当于告诉了系统,如果这个值发生了变化,就执行某个回调函数。
    实现方式可能是:
    系统设置 gpio 的中断使能寄存器。同时注册这个设备对应 irq 编号的处理函数。
    当这根线变化的时候, gpio 对应的控制器上的硬件(因为中断使能寄存器打开)检测到(有可能是轮询; 也可能是硬件上做一个带延时的电路,如果与当前值异或所得结果为 1 ,说明发生了变化),向处理器的中断线发了信号。
    处理器接到信号,根据来的线和种类,在内存中查找对应 irq 编号的处理函数,然后执行
    billlee
        17
    billlee  
       2016-08-18 23:34:00 +08:00
    @SuperFashi epoll 在没有事件发生的时候会阻塞,进程进入睡眠状态。硬件中断经过内核里的一系列 dispatch 后最后会把等待这个事件的进程唤醒。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5728 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 40ms · UTC 02:55 · PVG 10:55 · LAX 18:55 · JFK 21:55
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.