python3.7 中的 async/await 以及 asyncio 问题

2019-07-16 23:36:22 +08:00
 waibunleung

有一段代码:

import asyncio

async def crawl_page(url):
    print('crawling {}'.format(url))
    sleep_time = int(url.split('_')[-1])
    await asyncio.sleep(sleep_time)
    print('OK {}'.format(url))

async def main(urls):
    tasks = [asyncio.create_task(crawl_page(url)) for url in urls]
    for task in tasks:
        await task

%time asyncio.run(main(['url_1', 'url_2', 'url_3', 'url_4']))

########## 输出 ##########

crawling url_1
crawling url_2
crawling url_3
crawling url_4
OK url_1
OK url_2
OK url_3
OK url_4
Wall time: 3.99 s

我想问在 main 函数中的 for 循环处,原意是等待所有任务结束。但是遇到第一个 await 时不会直接跳出整个 for 循环吗?还是说只是会跳过当前的一轮循环?还是说 for 循环对于 await 其实有特别的处理对待?

我也知道这个和 python 的事件循环有关系,但是在网上找了不少资料都没有很能说清楚个大概的,希望 v 友们能给我解个惑,python 的事件循环是怎么样的?

5502 次点击
所在节点    Python
48 条回复
wwqgtxx
2019-07-17 14:31:34 +08:00
await 的意思是阻塞自己,等待别人结束
在调度器看来,你调用了 await 就把你当前的任务暂停,然后去做别的事,当你等待的任务结束了再择机继续执行当前任务(注意不是立刻执行,是择机执行)
silentsee
2019-07-17 14:40:31 +08:00
@waibunleung 我怎么感觉这个是个 bug。。。我把 await tasks[0]放到 await tasks[2]前面就能提前输出了。。。
wwqgtxx
2019-07-18 00:03:10 +08:00
@silentsee 本质上协程和线程调度一样,在没有锁、等待条件这些控制因素下并不保证调度顺序,所以在实现上无论如何实现都不属于 bug
waibunleung
2019-07-18 15:59:47 +08:00
@wwqgtxx 那这么说的话不应该在 await 自己等待别人的时候输出两句 print 吗?为什么是最后才输出呢?
wwqgtxx
2019-07-18 16:50:36 +08:00
@waibunleung 你自己都在等待别人了,怎么还能同时输出呢
waibunleung
2019-07-18 16:57:58 +08:00
@wwqgtxx 你说的有点道理,我再梳理一下
dingyaguang117
2019-07-23 13:44:12 +08:00
最后那段代码的运行结果跟我的理解不一样啊

感觉在 node 中应该不是这个结果,虽然我也没试过
dingyaguang117
2019-07-23 14:10:44 +08:00
我的理解大概是这样的,await 只保证同一段代码前后执行顺序,但是不能保证各个协程同时 await 时候的顺序

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

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

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

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

© 2021 V2EX