(也欢迎以更好的形式提出这个问题的一些帮助)
我正在考虑实施与互联网完全无关的异步软件。我还获得了Twisted Network Programming Essentials的副本,这是相当令人失望的。它,以及几乎所有其他教程,似乎只是将扭曲视为一个网络客户端,使用内置的事件处理程序,并默默使用内置的胶水代码,这很难概括。
对于上下文,我的应用程序希望使用serial / pyserial与硬件设备通信,并使用Qt提供gui。我甚至没有接近我开始担心Qt反应堆(它看起来是一堆蠕虫的另一个承诺)或移植到Windows的地步。
首先,我使用了一个扭曲的选择反应器,我已经添加了一个处理udev事件的Protocol + FileDescriptor。到目前为止我的工作原理是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.callWhenRunning()
调用函数reactor.run()
。 fileDescriptor按预期调用eventReceived函数。如果它有帮助,我可以在这里添加该代码。
我想要的是eventRecieved在反应堆中触发某种事件,而其他事情可以做出反应。这段代码不应该关心谁在消费它,而且代码不应该关心谁生成它。这些事件之间的距离很远,我似乎无法找到一个能够干净利落地完成这项工作的界面。事件预计相对不频繁,但它们永远不会结束#39;如果要使用延迟,则必须采用某种方式来刷新'本身等待下一个事件。处理此类事件的常用模式是什么?
编辑:
为了后人和其他任何人看,其余的代码:
(来自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
处启动答案 0 :(得分:4)
我想要的是eventRecieved在反应堆中触发某种事件,而其他事情可以做出反应。这段代码不应该关心谁在消费它,并且代码不应该关心谁生成它。
在Twisted和Twisted-using应用程序中广泛使用的这种模式是“进行函数调用”(可能是方法调用)。
反应堆本身并不是一个好的单进程消息总线。尝试将其合二为一的动机很小,因为在一般情况下,函数调用本身工作得非常好,当你遇到不常见的专业案例时,他们不会这样做。实际上很难做出好的事情(而且一旦你这样做,你仍然只为Twisted的一小部分观众提供服务)。
您的代码已经包含了我正在谈论的那种事情的示例。当我(我猜测)某些事件来自udev系统时,UdevMonitor
会调用UdevMonitorListener.eventReceived
。
重复一遍。为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(...)
另请注意,我将基类更改为object
。对于Protocol
实现,IProtocol
是一个有点方便的基类 - 但这不是UdevMonitorListener
的基础,所以Protocol
不是基类的好选择