Python异步事件和串行异步?

时间:2020-10-30 17:02:09

标签: python python-asyncio

我有代码(python类,我称其为Arduino),该代码将控制数据包写入串行端口(使用serial_asyncio),并且该串行端口回复确认数据包。但是,远程设备也会将事件数据包随机发送到python端。我希望类向实例化我的类的类提供解码后的数据包(我将其称为Controller)。我对如何处理感到困惑。

我首先想到的是提供对Arduino类的回调:

class Controller:
    def __init__(self):
        self.arduino = Arduino("/dex/ttyS0", self._serialPacketCallback)

    def _serialPacketCallback(self, obj: dict):
        pass # handle spontaneous event packet from remote

但这似乎不是很异步。什么是异步方式?我认为这看起来像:

class Controller:
    def __init__(self):
        self.arduino = Arduino("/dex/ttyS0")

    async readEventPacket(self):
        pass

    #somewhere, not sure where, or how to start it:
    async def _handleEvents(self)
        while True:
            event = await self._readEventPacket()

    async def start(self):
        await self.arduino.start()
        await asyncio.wait([self._handleEvents()])

if __name__ == '__main__':
    controller = Controller()
    loop = asyncio.get_event_loop()
    loop.create_task(controller.start())    
    loop.run_forever()

我环顾四周,并且看到使用回调多处理管道其他事件循环的建议,我相信他们能奏效,但我不确定正确的方法是什么。对我来说,我不想启动任何其他事件循环或线程,导致我认为回调是最好的,但这不是非常异步的,我想知道如何在没有其他事件循环的情况下以异步方式进行操作或回调。

我想表达的另一个担忧是,我希望像Arduino类那样松散耦合,将在其他控制器中使用。

旁注:我不确定在Python中何时需要创建新的事件循环吗?

另一个问题:Arduino类如何生成事件并让Controllerawait self._readEventPacket()中进行拾取?

1 个答案:

答案 0 :(得分:0)

关于asyncio的好处是,您始终可以将基于回调的接口转换为基于协程的接口,反之亦然。

假设您的Arduino类实现了一个基于回调的接口,如下所示(未经测试):

class Arduino:
    def __init__(self, device, callback):
        self._device = device
        self._callback = callback

    async def start(self):
        reader, writer = await serial_asyncio.connect(url=self._device, baudrate=115200)
        while True:
            data = await reader.read(1024)
            self._callback(data)

您可以使用队列将该接口转换为基于协程的接口:

def callback_to_coro():
    # Return two functions, one that can be passed as callback to
    # code that expects it, and the other a coroutine that can be
    # awaited to get the values the callback was invoked with.
    queue = asyncio.Queue()
    return queue.put_nowait, queue.get

使用该代码,您可以像这样实现Controller.read_event_packet

class Controller:
    def __init__(self):
        callback, wait = callback_to_coro()
        self.arduino = Arduino("/dex/ttyS0", callback)
        self.read_event_packet = wait