python使用协程实现udp_python的asyncio是否支持UDP网络的协同路由API?

今天晚上,我正在浏览python asyncio模块文档,为我的一个课程项目寻找一些想法,但是我很快发现python的标准aysncio模块可能缺少一些特性。在

如果你浏览一下文档,你会发现有一个基于回调的API和一个基于协程的API。回调API可以用于构建UDP和TCP应用程序,而协程API似乎只能用于构建TCP应用程序,因为它使用流式API。在

这给我带来了一个问题,因为我正在为UDP网络寻找一个基于协程的API,尽管我确实发现asyncio支持低级的基于协程的socket方法,比如^{}和{a2},但是UDP联网的关键API recvfrom和{}并不存在。在

我想写一些代码,比如:async def handle_income_packet(sock):

await data, addr = sock.recvfrom(4096)

# data handling here...

await sock.sendto(addr, response)

我知道可以使用回调API等效地实现这一点,但这里的问题是回调不是协程而是常规函数,因此在它中您无法将控制权交回事件循环并保持函数的执行状态。在

看看上面的代码,如果我们需要在数据处理部分做一些阻塞IO的操作,那么只要我们的IO操作也在协程中完成,那么协程版本就不会有问题:

^{pr2}$

只要我们使用await,事件循环就会从该点开始获取控制流来处理其他事情,直到IO完成。但遗憾的是,这些代码目前还不可用,因为我们在asyncio中没有socket.sendto和{}的协同程序版本。在

我们可以使用传输协议回调API来实现这一点:class EchoServerClientProtocol(asyncio.Protocol):

def connection_made(self, transport):

peername = transport.get_extra_info('peername')

self.transport = transport

def data_received(self, data):

info = requests.get(...)

response = generate_response_from_info(info)

self.transport.write(response)

self.transport.close()

我们不能在那里await一个协程,因为回调不是协程,使用上面这样的阻塞IO调用会在回调中暂停控制流,并阻止循环处理任何其他事件,直到IO完成

另一个推荐的实现思想是在data_received函数中创建一个Future对象,将其添加到事件循环中,并将所需的任何状态变量存储在Protocol类中,然后显式地将控制权返回给循环。虽然这可以工作,但它确实创建了许多复杂的代码,在协同程序版本中,这些代码在任何情况下都不需要。在

另外,here我们有一个使用非阻塞套接字和add_reader处理UDP套接字的示例。但是与协同程序版本的几行代码相比,代码看起来仍然很复杂。在

我想说的是,协同程序是一个非常好的设计,它可以在一个线程中利用并发的能力,同时也有一个非常简单的设计模式,可以节省脑力和不必要的代码行,但是,在我们的asyncio标准库中,让它为UDP网络工作的关键部分确实缺乏。在

你们觉得怎么样?在

另外,如果对支持这种UDP网络API的第三方库有什么建议,我将非常感谢我的课程项目。我发现Bluelet很像这样的东西,但它似乎没有被积极地维护。在

编辑:

似乎这个PR确实实现了这个特性,但是被asyncio开发人员拒绝了。开发人员声称所有函数都可以使用create_datagram_endpoint(),即协议传输API来实现。但是正如我在上面讨论过的,与在许多用例中使用回调API相比,协同路由API具有简单的优点,很不幸我们没有UDP。在


版权声明:本文为weixin_30488255原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。