【问题标题】:Twisted Patterns for Event Handling事件处理的扭曲模式
【发布时间】:2015-03-19 20:20:28
【问题描述】:

(也欢迎帮助以更好的形式形成这个问题)

我正在寻找 twisted 来实现一个与互联网完全无关的异步软件。我还获得了一份令人失望的 Twisted Network Programming Essentials 的副本。它和几乎所有其他教程一样,似乎只将twisted 视为网络客户端,使用内置事件处理程序并静默使用难以概括的内置胶水代码。

对于上下文,我的应用程序希望使用串行/pyserial 与硬件设备通信,并使用 Qt 提供一个 gui。我什至还没有接近开始担心 Qt 反应器(这似乎是一罐蠕虫的另一个承诺)或移植到 Windows 的地步。

首先,我使用了一个扭曲的选择反应器,我在其中添加了一个处理 udev 事件的协议 + 文件描述符。到目前为止我所做的工作,因为 udev 事件触发了协议中的一个函数(eventReceived)。 以下是协议及其添加到反应器的方式:

class UdevMonitorListener(Protocol):
    def __init__(self, _reactor=None):
        if _reactor is not None:
            self._reactor = _reactor
        else:
            self._reactor = reactor
        self.subsystem = 'tty'
        self.monitor = None

    def startListening(self):
        logger.info("Starting UdevMonitorListener")

        self.monitor = UdevMonitor(self._reactor, self, self.subsystem)
        self.monitor.startReading()

    def eventReceived(self, action, device):
        if device in connected_devices.udev_ports:
            if action == u'remove':
                connected_devices.remove_by_udev_port(device)
        if action == u'add':
            if is_device_supported_from_udev_port(device):
                if device not in connected_devices.udev_ports:
                    connected_devices.append_by_udev_port(device)


def init(_reactor=None):
    monitor_protocol = UdevMonitorListener(_reactor)
    monitor_protocol.startListening()

函数init()reactor.run() 之前由reactor.callWhenRunning() 调用。 eventReceived 函数按 FileDescriptor 的预期调用。如果有帮助,我也可以在此处添加该代码。

我希望 eventRecieved 触发反应器中的某种事件,其他东西可以对其做出反应。该代码不应该关心谁在使用它,该代码也不应该关心谁在生成它。这些事件之间的距离很少,而且我似乎无法找到一个能够干净利落地执行此操作的界面。预计这些事件不会相对罕见地发生,但它们永远不会“结束”。如果要使用 deferred,它必须有某种“刷新”自身的方式来等待下一个事件。处理此类事件的常用模式是什么?

编辑:

为了后代和其他人看,其余的代码:

(来自https://gist.github.com/dpnova/a7830b34e7c465baace7

class UdevMonitor(FileDescriptor):
    """
    File Descriptor for pyudev.Monitor.
    @see: U{http://packages.python.org/pyudev/api/monitor.html}.
    """
    def __init__(self, _reactor, protocol, subsystem=None):
        FileDescriptor.__init__(self, _reactor)

        # Set up monitor
        context = pyudev.Context()
        self.monitor = pyudev.Monitor.from_netlink(context)
        if subsystem:
            self.monitor.filter_by(subsystem=subsystem)

        # Connect protocol
        assert isinstance(protocol, UdevMonitorListener)
        self.protocol = protocol
        self.protocol.makeConnection(self)

    def fileno(self):
        """
        Return monitor's file descriptor.
        """
        return self.monitor.fileno()

    def startReading(self):
        """
        Start waiting for read availability.
        """
        logger.debug("starting udev monitor fd")
        self.monitor.start()
        FileDescriptor.startReading(self)

    def doRead(self):
        """
        An event is ready, decode it through Monitor and call our protocol.
        """
        logger.debug("udev reports event available")
        event = self.monitor.receive_device()
        if event:
            action, device = event
            self.protocol.eventReceived(action, device)

    def writeSomeData(self, data):
        raise IOError("You can't write to a udev Monitor")

或者包含 connected_devices 和设备搜索的完整模块在 https://gist.github.com/chintal/2511459c02a9767deb5d

【问题讨论】:

  • 您可能想要修复您的代码格式。在当前版本的问题中,缩进大多是错误的。

标签: python twisted


【解决方案1】:

我希望 eventRecieved 触发反应器中的某种事件,其他东西可以对其做出反应。该代码不应该关心谁在使用它,该代码也不应该关心谁在生成它。

在 Twisted 和使用 Twisted 的应用程序中广泛使用的模式是“进行函数调用”(可能是方法调用)。

reactor 本身并不能构成良好的单进程消息总线。尝试将其合二为一的动力很小,因为函数调用本身在一般情况下工作得很好,而当你遇到不太常见的特殊情况时,实际上很难做出好的事情(而且曾经你这样做了,你仍然只为 Twisted 的一小部分可能的观众提供服务。

您的代码已经包含我正在谈论的那种事情的示例。 UdevMonitor 调用 UdevMonitorListener.eventReceived 当(我猜)某种事件从 udev 系统中出来时。

重复一遍。给你的UdevMonitorListener 一个对另一个对象的引用,并在适当的时候对该对象调用一些方法。例如:

class UdevMonitorListener(object):
    def __init__(self, device_listener, _reactor=None):
        ...
        self.device_listener = device_listener

    def eventReceived(self, ...)
        ...
        self.device_listener.some_device_thing_happened(...)

另请注意,我将基类更改为objectProtocolIProtocol 实现的一个比较方便的基类 - 但 UdevMonitorListener 不是这样,所以 Protocol 不是基类的好选择。

【讨论】:

  • 我的印象是协议会提供一些反应堆需要与之交互的基本方法。 Protocol / IProtocol 有用的实例有哪些?是在有一定字节数的 DataRecieved 时吗?
  • 这里的部分想法是反应器不需要与您在这里所做的事情进行交互。它已经完成了它的工作(它为您提供了 udev 就绪通知),其余的取决于您。关于协议和 IProtocol - 是的。它用于处理从 TCP 连接获得的字节流。
猜你喜欢
  • 1970-01-01
  • 2011-10-21
  • 1970-01-01
  • 2017-09-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多