如何使Python对象可等待

17

Python 3.5.1中,可以利用await/async,但使用它(据我所知)需要一个可等待对象。 可等待对象是一个定义了返回迭代器的__await__()方法的对象。更多信息请点击此处。 但我找不到任何具有这种特性的示例,因为大多数示例都使用类似asyncio.sleep(x)的形式来模拟可等待对象。

我的最终目标是创建一个简单的websocket串行服务器,但我无法通过第一步。 这是我的(不工作的)代码。

import serial
import asyncio

connected = False
port = 'COM9'
#port = '/dev/ttyAMA0'
baud = 57600
timeout=1

class startser(object):

    def __init__(self, port, baud):
        self.port = port
        self.baud = baud       

    def openconn(self):       
        self.ser = serial.Serial(port, baud)

    async def readport(self):
        #gooo= await (self.ser.in_waiting > 0)
        read_byte = async self.ser.read(1).decode('ascii')        
        self.handle_data(read_byte)
        print ("42")  

    def handle_data(self, data):
        print(data)

serr=startser(port,baud)
serr.openconn()

loop = asyncio.get_event_loop()
#loop.run_forever(serr.readport())
loop.run_until_complete(serr.readport())
loop.close()

print ("finitto")

#with serial.Serial('COM9', 115200, timeout=1) as ser:
    #x = ser.read()          # read one byte
    #s = ser.read(10)        # read up to ten bytes (timeout)
    #line = ser.readline()   # read a '\n' terminated line`

1
serial.Serial() 不是可等待对象。最终,您需要创建可等待的 I/O 原语,以便知道如何推迟执行,直到数据可用。这可不是易如反掌的事情。我认为目前还没有串口可等待的方法。 - Martijn Pieters
@MartijnPieters 我认为串行原理与处理某些持久的数学算法相同。我不知道如何创建可等待对象本身(如所述的文档链接)。因为,虽然串行不可等待,但它可能会被包装。我承认我对Python不是很了解,但我会尝试,并且我希望至少在这里更详细地解释第一步(创建可等待对象)。 - nekitip
由于还没有建议,您应该查看:https://docs.python.org/3.5/library/collections.abc.html#collections.abc.Awaitable。我不完全确定您想要实现什么,但是从文档中继承Awaitable抽象类将允许您创建自定义的“可等待”对象。 - Dan Temkin
1个回答

17

我猜这个问题还没有答案,因为问题不够清晰。你说得对,

可等待对象是定义了一个返回迭代器的__await__()方法的对象

这里没有什么要补充的。只需从该方法返回迭代器。

唯一需要理解的是它的工作原理。我的意思是,asyncio或其他类似框架如何在单个线程中实现并发。高层次上很简单:将所有代码组织成迭代器,然后依次调用它们,直到值耗尽。

例如,如果您有两个迭代器,第一个产生字母,第二个产生数字,事件循环调用第一个并获得'A',然后调用第二个并获得1,然后再次调用第一个并获取'B',以此类推,直到完成迭代器。当然,在产生下一个值之前,这些迭代器中的每一个都可以执行任何您想要的操作。但是,执行时间越长,切换任务之间的暂停时间就越长。必须确保每个迭代都很短:

  1. 如果有内部循环,请使用async for - 这将允许在没有显式yield的情况下切换任务。
  2. 如果有很多代码需要执行几十甚至几百毫秒,请考虑将其重写为较小的片段。对于旧代码,可以使用诸如asyncio.sleep(0)之类的技巧,这是允许asyncio在此处切换任务的允许。
  3. 没有阻塞操作!这是最重要的。假设您执行了像socket.recv()这样的操作。所有任务都将停止,直到此调用结束。这就是为什么在标准库中称之为async io:必须使用它们的所有I/O函数的实现,例如BaseEventLoop.sock_recv()

我建议您从以下文档开始(如果您还没有开始):


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接