我使用Tornado和asyncio编写了异步程序,但是我意识到我不理解异步任务是如何完成的。
例如,让我们看一下http://www.tornadoweb.org/en/stable/guide/async.html#examples中的异步读取。
目前我的理解是:
- 当
fetch
产生Future
时,处理程序被挂起。 -
Future
加入IOLoop
通过http://www.tornadoweb.org/en/stable/ioloop.html#tornado.ioloop.IOLoop.add_future -
Future
完成,IOLoop
调度协程重新激活,使其能够完成。
我不明白的是Future
在步骤3"完成"并调用它的完成回调。我认为只有一个线程,那么Future
如何"在后台工作"并获得控制,以便它可以调用回调?
IOLoop打开一个套接字到您正在获取的远程服务器,并将该套接字添加到文件描述符列表中,它正在使用epoll或类似的系统调用等待IO。
当循环没有执行你的代码时——例如,当你的处理程序被yield
暂停时,循环正在等待IO,这里:
https://github.com/tornadoweb/tornado/blob/master/tornado/ioloop.py L862
当它接收到一个IO事件时——例如,当远程服务器发送一些响应字节时——Tornado找到正在等待该事件的回调并执行它。
有关事件循环的示例实现,请参见使用asyncio协程的Web Crawler。