Python 3.x 如何编写Python异步串行异步读取器?

Python 3.x 如何编写Python异步串行异步读取器?,python-3.x,python-asyncio,Python 3.x,Python Asyncio,我正在把一些C++代码移植到Python,我花了好长时间才知道如何为串行字节提供一个OnCalter处理器。我正在使用 import serial_asyncio class Arduino: #comms is with an Arduino in serial mode) async def connect(self, serial_port): (self.serial_reader, self.serial_writer) = await ser

我正在把一些C++代码移植到Python,我花了好长时间才知道如何为串行字节提供一个OnCalter处理器。我正在使用

import serial_asyncio
class Arduino: #comms is with an Arduino in serial mode)
    async def connect(self, serial_port):
        (self.serial_reader, self.serial_writer) = await 
        serial_asyncio.open_serial_connection(url=serial_port, baudrate=115200)
        print("serial opened:", serial_port)
        self.buffer = b""

    async def recv(self, data):
        self.buffer += data
        self.process_buffer(self.buffer)

if __name__ == '__main__':
     ardunio = Arduino("/dev/ttyS0")         
     loop = asyncio.get_event_loop()
     loop.run_until_complete(ardunio.connect())
     loop.run_forever()
但是,我不知道如何将recv处理程序修补到read。 我,我可以:

connect(&QAbstractSocket::readyRead, &Arduino::handleBytes);
在节点中:

arduino.on('data', line => console.log(line))
在Python中,似乎没有任何明显的答案?如何获取要传递到Arduino.receive(self,data)的串行端口字节

但是,我不知道如何将recv处理程序修补到read

open\u serial\u connection
不是一个基于回调的接口,它返回一对流,这些流通过协同路由公开内容。这使您可以像编写阻塞代码一样与串行端口通信,即不使用回调和缓冲区来建立数据。例如(未经测试):

类似于
StreamReader.read
的协同程序看起来会阻止等待数据,但实际上它们只是暂停当前协同程序,让事件循环执行其他操作。这允许您在等待数据从串行端口到达时轻松表示超时或进行其他处理

如果仍然需要回调,例如,因为需要与C API通信,则有两个选项:

  • 使用较低级别的
    创建串行连接
    功能。它接受一个继承
    asyncio.Protocol
    的类型,您可以在其中定义钩子,如
    data\u received
    (作为回调,而不是协程),这与您建模
    Arduino
    类的方式非常接近

  • 继续使用协同路由API,但使用
    add\u done\u callback
    注册一个回调,以便在协同路由就绪时运行

后者的一个例子是:

async def main():
    reader, writer = await serial_asyncio.connect(url="/dev/ttyS0", baudrate=115200)
    # Python equivalent of arduino.on('data', x):
    # 1. call reader.read() but don't await - instead, create a "future"
    # which works like a JavaScript Promise
    future = asyncio.ensure_future(reader.read(1024))
    # register a done callback when the result is available
    future.add_done_callback(future, lambda _: print(repr(future.result())))
    # go do something else - here we wait for an event just so main()
    # doesn't exit immediately and terminate our program
    await asyncio.Event().wait()

asyncio.run(main())

但是,除非您与C进行通信,否则我看不出使用这种样式比普通的async/await有什么好处。

谢谢。我仍然对我以前的异步经验感到困惑。在以前的所有情况下,我都能够请求读取与缓冲区中等待的字节数相匹配的长度。在Python中,对于完全异步(一般意义上,不确定何时或谁将首先发送字节)通信,我只需要在循环中读取(1)?我很困惑,这让我看起来像是在做一些恶作剧。但是,在你的帮助下,我能够让它工作!这比看起来要简单得多@UserOneFourTwo我个人没有使用过异步串行,但是对于通用异步IO,您肯定不需要在循环中调用
read(1)
。类似于
wait reader.read(1024)
的内容将为您提供尽可能多的数据,1024是上限。但是如果只有3个字节到达,你应该立即得到它们。谢谢。感谢您的回答,在让它工作后进行了实验,似乎只需简单的read()就可以了。
async def main():
    reader, writer = await serial_asyncio.connect(url="/dev/ttyS0", baudrate=115200)
    # Python equivalent of arduino.on('data', x):
    # 1. call reader.read() but don't await - instead, create a "future"
    # which works like a JavaScript Promise
    future = asyncio.ensure_future(reader.read(1024))
    # register a done callback when the result is available
    future.add_done_callback(future, lambda _: print(repr(future.result())))
    # go do something else - here we wait for an event just so main()
    # doesn't exit immediately and terminate our program
    await asyncio.Event().wait()

asyncio.run(main())