Python 中关于 async/await 的疑问

2019-01-25 11:46:36 +08:00
 aoscici2000

对于协程, 一些使用装饰器或者队列的实例基本都能理解, 但是这个 async/await 看了很多实例也不太懂该怎么理解. 网上 90%的教程的例子大概基本都是这样的:

async def func():
    print("start...")
    r = await asyncio.sleep(5)
    print("end...")

这个 asyncio.sleep()从一开始就定义是非阻塞的, 问题是它到底是通过什么方式实现非阻塞的呢? 换成我自己的处理函数, 这个函数应该用什么方式协程非阻塞的?

2739 次点击
所在节点    Python
10 条回复
shylockhg
2019-01-25 11:49:55 +08:00
asyncio.sleep 就是阻塞的,这里是模拟 IO 等阻塞过程
shylockhg
2019-01-25 11:56:58 +08:00
@shylockhg 说错应该叫非阻塞
aoscici2000
2019-01-25 12:01:27 +08:00
@shylockhg 我疑问就是这里了, 这个非阻塞是通过什么方式实现的?
so1n
2019-01-25 12:07:09 +08:00
@aoscici2000 通过事件循环,3.4 时是 yield
aoscici2000
2019-01-25 12:10:53 +08:00
@so1n 意思是该开线程还得开, 该 yield 还得 yield, 就是换了个词而已 ???
silkriver
2019-01-25 12:23:33 +08:00
不开线程,异步 io 的意思就是 io 操作不会阻塞当前线程
meik2333
2019-01-25 12:31:41 +08:00
https://github.com/python/cpython/blob/97cf0828727ac2a269c89c5aa09570a69a22c83c/Lib/asyncio/tasks.py#L593
将事件添加到事件循环里,由事件循环调度。

scrapy 也是用这种方法实现每分钟打印一次日志的。
Trim21
2019-01-25 12:34:12 +08:00
你可以看看源码, asyncio.sleep 是通过在事件循环里 call_later 来实现的. 在这个 async 函数中阻塞, 但是不会阻塞事件循环.
作用就是模拟异步 io 操作.
所以换成你自己的处理函数的时候, 比如是链接数据库, http 请求这样的可以异步化的, 就用类似的异步化的库(比如 aiohttp, aioredis, motor 等等)来 await query()调用.
如果不能异步化的就开线程用 ThreadPoolExecutor 转成异步调用.
aijam
2019-01-25 12:39:05 +08:00
解释线程 /异步 /非阻塞 /event loop 的文章网上一大堆,你看了也不会真的懂。
先熟悉熟悉这个包:
https://docs.python.org/3/library/selectors.html#module-selectors
https://docs.python.org/3/library/select.html#module-select
他们说的再多虚头巴脑都扯淡,核心内容就是 selector。
xinXinDaWang
2019-01-30 16:17:30 +08:00
那你要看很多了,future, loop, epoll 都要看, 是他们相互协作形成的,await==yield from 只是一个方便的写法,也可以用回调来写,只是会麻烦一些

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

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

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

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

© 2021 V2EX