如何让 asyncio 按照优先级顺序来执行执行几个有优先级的可等待对象?

2020-12-09 15:17:40 +08:00
 abersheeran

假设事件循环里有一百万个可等待对象,其中一万个可以继续进行了,其他的仍然在等待。那么如何让这一万对象按照优先级顺序顺序执行?

我猜测要从 asyncio 源码下手,有没有读过源码的大佬给个大概的可入手的地方,比如事件循环是在哪里遍历对象判断可执行的?或者有现成的仓库?(谷歌、必应、百度过,没搜到,所以我猜大概率没有,就算有,也是藏得很深的)

2528 次点击
所在节点    Python
19 条回复
wellsc
2020-12-09 15:19:55 +08:00
abersheeran
2020-12-09 15:24:58 +08:00
@wellsc 我想问的是优先级,而不是命名。
ruanimal
2020-12-09 15:29:51 +08:00
@abersheeran 把任务放优先队列里就行了
BBrother
2020-12-09 15:32:00 +08:00
可不可以全局维护一个优先级表,每个 task 执行前先查询优先级,如果不是最高的,就再把自己加入到事件循环中?
geebos
2020-12-09 15:34:29 +08:00
自定义一个 eventloop,在 task 类上添加一个优先级,在 select 的时候把准备好的任务添加到优先队列里再执行,但是感觉性能不太好。我建议分几个优先级,不同优先级有执行顺序,相同优先级的按到达顺序执行,这样在选取的时候遍历一遍就可以。
wellsc
2020-12-09 15:40:31 +08:00
@abersheeran 按照命名排序不就好了
abersheeran
2020-12-09 16:08:24 +08:00
不回复以上回复,是因为我不想开口骂人。

有没有真正 hack 过 asyncio 事件循环的大佬能给点具体的建议?
BBCCBB
2020-12-09 16:27:38 +08:00
每个对象加一个 condition?
然后后一个对象等待前一个对象的 condition signal. 看看这样可不可行
BBCCBB
2020-12-09 16:28:28 +08:00
或者楼上说的放优先队列里一个一个拿出来跑也没问题呀.
abersheeran
2020-12-09 16:45:20 +08:00
@BBCCBB 问题里我觉得我问的很明确了,我想要的是具体的入手点或者现有的库,而不是思路。优先级队列这种入门级的思路,我也能想到啊,关键是这个队列放在哪?在哪里把元素放进去?事件循环里哪个 API 可以用来 hack 这种操作?我想要的是这些。
BBCCBB
2020-12-09 16:58:56 +08:00
当我没说.

假设事件循环里有一百万个可等待对象,其中一万个可以继续进行了,其他的仍然在等待。那么如何让这一万对象按照优先级顺序顺序执行?

大家回答的你第一个问题.
hgrx
2020-12-09 16:59:21 +08:00
不想骂人可还行,在论坛发了这个帖子这个帖子就是你家了?别人不能进来谈一下看法?你只是发起了一个讨论,你没有拥有这个帖子,你也没资格指责别人怎么不如你意了
abersheeran
2020-12-09 17:10:47 +08:00
@BBCCBB ……好的,下次我尽量让问题重点更显眼一些。

@hgrx 你当然有发评论的权力,我同样有反驳你发的评论的权力,包括对你们评论的批评和猛烈批评,我只是用了一个口语化的形容——“骂”。怎么?只讲你们的权力,我就是没人权的人了?
lyzh
2020-12-09 17:31:00 +08:00
@hgrx 所以他没开口骂人你都觉得不爽,那我来阴阳你一下你你开心咯?
se77en
2020-12-09 20:23:16 +08:00
asyncio.wait 有个 return_when 参数,可以参考一下这个 https://stackoverflow.com/a/48567863/2050626
abersheeran
2020-12-09 22:29:00 +08:00
@se77en 谢谢,这个我也搜到了。不过它这个并没有真的实现一个按照优先级执行的事件循环。

这个问题我打算给它沉掉,有一个看过源码的大佬说这个搞不定,没有对应的 API 。符合我最开始的推断,只能像 trio 一样重写一套,成本太高了。唉。不过还是谢谢你花时间帮我搜答案。
linw1995
2020-12-10 11:27:55 +08:00
1. 让各个 asyncio.Task 带上优先级
可以通过 loop.set_task_factory 让各个 coroutines 有优先级,可以不修改 Task 对象,优先级存在 context 里就好了。这样其产生的新 task 可以继承这个优先级

2. 修改 loop._run_once 使其按优先级执行(不行)
_run_once 是在跑一个个 callbacks,所以没法用来使 asyncio.Task 按优先级执行

所以就只能在 asyncio.Task.__step 这里搞幺蛾子了,维持一个全局的优先级堆,执行 __step 先检查一下自己的优先级在不在堆顶,看该不该继续执行,不该就重新 call_soon 。

按这个思路应该可以搞起来
abersheeran
2020-12-10 12:05:09 +08:00
@linw1995 这样就是在 asyncio 里,手动创建一个由 Task 作为基本单位的带优先级的事件循环。看起来可行!感谢!

这个思路我是真没想到,不需要去走 loop 的接口,只要调整 Task,保证每个可等待对象都被 Task 包装起来就行了。太有意思了。是我之前的想法钻牛角尖了😭
joApioVVx4M4X6Rf
2021-07-21 19:12:19 +08:00
请问后来解决了吗?怎么解决的?

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

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

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

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

© 2021 V2EX