初学 python,大家帮忙看看这段协程代码,运行结果想了半天还没想通

2016-11-03 08:59:30 +08:00
 nicegoing
import logging; logging.basicConfig(level=logging.INFO)

import asyncio, os, json, time
from datetime import datetime

from aiohttp import web

def index(request):
    logging.info('server response...')
    return web.Response(body=b'<h1>Awesome</h1>')

async def init(loop):
    app = web.Application(loop=loop)
    app.router.add_route('GET', '/', index)
    logging.info('server before...')
    srv = await loop.create_server(app.make_handler(), '127.0.0.1', 9000)
    logging.info('server started at http://127.0.0.1:9000...')
    return srv

loop = asyncio.get_event_loop()
loop.run_until_complete(init(loop))
loop.run_forever()

我觉得运行的日志:

INFO:root:server before...
INFO:root:server response...
INFO:root:server started at http://127.0.0.1:9000...

结果正确的日志是:

INFO:root:server before...
INFO:root:server started at http://127.0.0.1:9000...
INFO:root:server response...

在我的理解里, python 执行到 await 应该暂停执行函数, TCP 协程结束后,才执行 server started at...这条日志。怎么函数一下子全部执行完了。

4495 次点击
所在节点    Python
14 条回复
cloverstd
2016-11-03 09:08:05 +08:00
因为你的 init 函数没有用 await init 调用
ifaii
2016-11-03 09:11:30 +08:00
async def init(loop):

学艺不精 看不懂-_-||
nicegoing
2016-11-03 09:17:13 +08:00
@cloverstd https://docs.python.org/3/library/asyncio-task.html#example-chain-coroutines
这是 python 的官方示例。这个例子调用的时候也没有 await 调用呀
```
import asyncio

async def compute(x, y):
print("Compute %s + %s ..." % (x, y))
await asyncio.sleep(1.0)
return x + y

async def print_sum(x, y):
result = await compute(x, y)
print("%s + %s = %s" % (x, y, result))

loop = asyncio.get_event_loop()
loop.run_until_complete(print_sum(1, 2))
loop.close()
```
sujin190
2016-11-03 09:20:45 +08:00
没错啊, create_server 只是 bing 了没有 listen 啊,所以立刻返回了, run_forever 才进行 listen 的行为
nicegoing
2016-11-03 09:21:05 +08:00
@ifaii 我也不懂,纠结中
sujin190
2016-11-03 09:21:58 +08:00
没错啊, create_server 只是 bind 了没有 listen 啊,所以立刻返回了, run_forever 才进行 listen 的行为
cloverstd
2016-11-03 09:29:53 +08:00
@nicegoing 你的 init 返回的是一个 future ,直接 init() 会当做普通函数来执行
ruoyu0088
2016-11-03 09:30:55 +08:00
loop.create_server 是创建一个服务器对象, await loop.create_server(...)是等待创建这个服务器对象,并不是等待这个服务器响应请求。
yufpga
2016-11-03 09:36:57 +08:00
await 的语义相当于 yield from(首先你得先搞清楚这个东西), 不要和 yield 这个鬼搞混淆了, 出现 async 和 await 支持的原因本就是为了使用写同步代码的方式写出异步的效果.在你这里, 正常逻辑考虑, 你的 server 都还没有创建, 怎么可能请求成功, 从而执行 index 函数.建议 debug 追踪下代码内部的执行逻辑,要熟悉其内部原理, 最好看一下 asyncio 的源码, 自己实现一下
nicegoing
2016-11-03 09:37:30 +08:00
@cloverstd
@sujin190
@ruoyu0088
谢谢大家,有点儿明白了。
nicegoing
2016-11-03 09:40:40 +08:00
@yufpga 感觉 yield from 和 yield 没什么大区别。谢谢,我去读读源码
yufpga
2016-11-03 09:57:13 +08:00
@sujin190 你的说法是有问题的, run_forever 并不是进行 server 的 listen 的行为,而是执行了一段类似与下面的代码
while not self.stopped:
events = selector.select(self.select_timeout)
if not events:
raise Exception('轮询超时')
for event_key, event_mask in events:
callback = event_key.data
callback(event_key, event_mask)
用来取出可读可写等事件, 其实就是通过事件循环驱动(通知)阻塞程序恢复执行
sujin190
2016-11-03 10:50:18 +08:00
@yufpga listen 做的事情也是这样的啊,有什么区别么
lytofb
2016-11-03 11:03:45 +08:00
没什么问题啊, win7 64 位 python 3.5.2

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/317617

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX