import asyncio
def foo(n):
print(f'--------- foo({n}) ----------')
async def main(loop):
loop.call_later(0.1, foo, 1)
loop.call_soon(foo, 2)
loop.call_at(loop.time() + 0.2, foo, 3)
await asyncio.sleep(1)
event_loop = asyncio.get_event_loop()
try:
event_loop.run_until_complete(main(event_loop))
finally:
event_loop.close()
有如上这段简单的代码.
在 main 函数中有 await asyncio.sleep(1)
,如果不写一行, 那么 loop.call_later(0.1, foo, 1)
和 loop.call_at(loop.time() + 0.2, foo, 3)
的结果都会看不到(sleep 的时间必须大于 delay 的时间), 这是为什么.
我的疑问在这里, Python asyncio 的事件循环机制是什么, event_loop.run_until_complete(main(event_loop))
, 这里的 run_until_complete
指的
到底是什么 complete
?
或者说有讲解 Python asyncio event loop 的好的资料告诉我也好.
1
lanpong 2018-09-24 13:30:30 +08:00 via iPhone 2
|
2
sujin190 2018-09-24 13:44:34 +08:00 via Android
main 函数返回,不是所有事件完成,没有 sleep,main 函数返回 ioloop 就结束了啊,call_later 自然不会执行
|
3
guyskk0x0 2018-09-24 13:47:40 +08:00 via Android
显然 run_until_complete 指的是你传入的 main()结束
|
4
so1n 2018-09-24 13:53:33 +08:00 1
可以看下这个: https://docs.python.org/3/library/asyncio-eventloop.html
run_until_complete 是指一个 future 运行为一个周期,也就是你传入的 main(event_loop),当没加入 await asynico.sleep()时,run_until_complete 会直接运行完 main(event_loop)然后就执行到你的 event_loop.close()直接关闭事件循环。而你代码中的 loop.call_*是把任务转交给 event_loop 运行,此时的 event_loop 已经关闭,就无法运行了。你可以使用 run_forever()保持事件循环不关闭 |
6
zhzer 2018-09-24 15:47:36 +08:00
其实道理不难,就是绕人,我就不献丑了
推荐《 fluent python 》虽然只用了一章讲协程,不过够了 |
8
so1n 2018-09-24 16:23:10 +08:00 1
@ltoddy 恩恩,差不多可以这样理解,不过 await asyncio.wait(tasks)就不一样了还是属于 main 的 future。
|
10
neoblackcap 2018-09-24 18:00:16 +08:00 1
为什么难理解,其实是大家看书查资料的方向错了。这里虽然是协程,但更多的是事件驱动编程,除了用上了 await 来解决以前的装饰器,还有一些默认的封装。但本质还是事件驱动编程。具体可以看 linux 网络编程,跟 epoll 相关的内容。现在大多数事件循环在 Linux 下都是封装 epoll,将对应的套接字以及回调函数注册到 epoll 实例上。抓住本质自然就会了解。其实很多现在这些框架的作者是默认你了解这部分内容的。
|
11
PythonAnswer 2018-09-25 07:49:20 +08:00 via iPhone
aio 建议从 3.4 走一遍。那时还没有 await。这玩意其实就是 yield 和 yield from。搞懂了就 ok 了。
不过用了一遍之后,可能还是大坑。 为啥不用 gevent 呢? |
12
ltoddy OP @neoblackcap 我觉得你说的很虚, linux 的 epoll 我知道,当初在看 node 以及 libuv 的时候学了.
我想反问,如果你会汇编,难道所有语言对你都是小 case 吗. 所以啊,别说的这么轻浮. |
13
ltoddy OP @PythonAnswer 你说的这个我在读流畅的 py 的时候就已经很熟悉了. 为什么不用 gevent, 很简单,我现在还是学生.
|
14
PythonAnswer 2018-09-25 12:19:36 +08:00 via iPhone
是学生就好好学吧。加油
|
15
zhzer 2018-09-25 13:59:06 +08:00 via Android
|
17
cosven 2018-09-25 14:55:15 +08:00 1
认同 so1n 的说法
之前写过一个非常简单(残疾)地 gevent demo,一百行左右,感觉可以帮助楼主理解 asyncio/gevent 等 https://gist.github.com/cosven/a251ca10c6c0c57c8b5dbd92fe131c2f 在 LZ 的例子中:main 是个协程,另外 call_later/call_soon/call_at 也会创建协程。后来,run_until_complete 只等待 main 结束,就关闭了 event_loop,当 event_loop 关闭了,其它协程自然就不会执行了。 如果 LZ 想让这几个协程都能执行完,可以用 loop.run_forever() 或者一些 asyncio.wait 等其它方法。 |
19
lolizeppelin 2018-09-26 00:34:22 +08:00 via Android
这玩意就是模仿现在 js dart 之类的 异步对象
python 以前也有个别扭的 future 库 他们要实现的功能都差不多 js dart 是原声实现 。 Python 靠 yied 实现 但是万变不离其宗 搞清楚目的就很好理解了 Python3 我没用过 瞎说的 2333 |