这个问题是由我的另一个问题推动的:如何在cdef中等待?
网上有大量的文章和博客文章asyncio,但它们都非常肤浅.我找不到任何有关如何asyncio实际实现的信息,以及I/O异步的原因.我试图阅读源代码,但它是成千上万行不是最高级别的C代码,其中很多处理辅助对象,但最重要的是,很难在Python语法和它将翻译的C代码之间建立连接成.
Asycnio自己的文档甚至没那么有用.没有关于它是如何工作的信息,只有关于如何使用它的一些指导,这些指导有时也会误导/写得很差.
我熟悉Go的coroutines实现,并且希望Python做同样的事情.如果是这种情况,我在上面链接的帖子中出现的代码就可以了.既然没有,我现在正试图找出原因.到目前为止我最好的猜测如下,请纠正我错在哪里:
async def foo(): ...实际上被解释为类继承的方法coroutine.async def实际上是通过await语句拆分成多个方法,其中调用这些方法的对象能够跟踪到目前为止通过执行所做的进度.await语句) ).换句话说,这是我尝试将某些asyncio语法"贬低"为更容易理解的东西:
async def coro(name):
print('before', name)
await asyncio.sleep()
print('after', name)
asyncio.gather(coro('first'), coro('second'))
# translated from async def coro(name)
class Coro(coroutine):
def before(self, name):
print('before', name)
def after(self, name):
print('after', name)
def __init__(self, name):
self.name = name
self.parts = self.before, self.after
self.pos = 0
def __call__():
self.parts[self.pos](self.name)
self.pos += 1
def …Run Code Online (Sandbox Code Playgroud) 默认情况下,asyncio同步运行协同程序.如果它们包含阻塞IO代码,它们仍会等待它返回.解决这个问题的方法是loop.run_in_executor()将代码转换为线程.如果线程在IO上阻塞,则另一个线程可以开始执行.所以你不要浪费时间等待IO调用.
如果您在asyncio没有执行者的情况下使用,那么您将失去这些加速.所以我想知道,为什么你必须明确地使用执行器.为什么不默认启用它们?(在下文中,我将重点关注http请求.但它们实际上只是作为一个例子.我对一般原则感兴趣.)
经过一番搜索,我找到了aiohttp.它是一个基本上提供asyncio和组合的库requests:非阻塞HTTP调用.使用执行程序,asyncio并且requests表现得非常像aiohttp.是否有理由实施新库,您是否因使用执行程序而支付性能损失?
回答了这个问题:为什么asyncio总是不使用执行程序?
Mikhail Gerasimov向我解释过,执行程序会启动操作系统线程并且它们会变得昂贵.因此,不将它们作为默认行为是有道理的.aiohttp比requests在执行程序中使用模块更好,因为它提供只有协同程序的非阻塞代码.
这让我想到了这个问题.aiohttp将自己宣传为:
用于asyncio和Python的异步HTTP客户端/服务器.
所以aiohttp是基于asyncio?为什么不asyncio提供只有协同程序的非阻塞代码呢?这将是理想的默认值.
或者aiohttp实现了这个新的事件循环(没有OS线程)本身?在那种情况下,我不明白他们为什么要宣传自己为基础asyncio.Async/await是一种语言功能.Asyncio是一个事件循环.如果aiohttp有自己的事件循环,那么应该有很少的交集asyncio.实际上,我认为这样的事件循环将比http请求更大.