异步大量请求,如何获得第一个有效的返回值?

2018-07-12 13:52:34 +08:00
 billgreen1
情景:
我的一个 list 中,有很多 future, 每个执行耗时不定。返回结果 None 或者 某个值。
future1..futuren 中,第一个不为 None 的值,就是我想要的。
如果用下面的语句
```python
result = yield [future1(), future2(), ....]
```
会把所有的都执行完。

但是有可能会有这种情况:
future1,future2 结果返回 None,future3 不为 None
我就可以直接取 future3 的结果了。


请教如何实现?
3758 次点击
所在节点    Python
16 条回复
noli
2018-07-12 14:13:32 +08:00
这种 polling 工作肯定都是库或者框架做的,然而你又没有具体说到底用哪个异步库或者框架。
creedowl
2018-07-12 14:14:48 +08:00
(换 js,用 promise
billgreen1
2018-07-12 14:17:40 +08:00
@noli 额,tornado,我是因为不想太限制
v2xe2v
2018-07-12 14:19:19 +08:00
结果入队列,然后轮训?
noli
2018-07-12 14:24:08 +08:00
@billgreen1
http://www.tornadoweb.org/en/stable/queues.html

4# @v2xe2v 思路是对的,实际上就是把结果入队列,取第一个。只不过这个队列不需要轮询这么费力而已。
lolizeppelin
2018-07-12 14:31:44 +08:00
包装一下 返回前 callback
janxin
2018-07-12 15:04:33 +08:00
你可以选择不用 yield,直接 add_done_callback
zhuweiyou
2018-07-12 15:13:42 +08:00
结果套同一个 func,判断第一个非 none 的做处理,其它的 abort
wb14123
2018-07-12 15:39:37 +08:00
所有 future 的结果都扔到一个 BlockingQueue 里面然后从这个里面取
bojoyzhou
2018-07-12 19:23:13 +08:00
@zhuweiyou 感觉这个方案最便捷
gjquoiai
2018-07-12 19:43:12 +08:00
我记得 pycon 2018 trio 的作者就讲了这个
so1n
2018-07-12 20:21:16 +08:00
不知道楼主的意思是不是这样的同时运行多个,然后获取返回的结果,如果是 None 忽略 不是就获取值并结束
task_list = []
done, pending = await asyncio.wait(task_list)
for task in done:
if task.result() != None:
result = task.result()
break
andyholo
2018-07-12 21:34:00 +08:00
rxPY 这种需求还是用专门库吧,比自己琢磨方便多了
billgreen1
2018-07-13 08:13:27 +08:00
@so1n 可能是我表述不清楚,其实是这样的:如果第一个返回的是 future3 且结果不为 None,那么我还得等 future1 和 future2。1..n 是有优先级顺序的。当 future i 返回,且有结果时,可以确定的是 i+1 到 n 是可以丢弃了,但是得等 future1 到 future (i-1)的结果
so1n
2018-07-13 08:39:58 +08:00
@billgreen1 所以你获取的顺序不是按执行结束时间排序而是按原来排列好的队列?如果是这样的话,简单点直接先遍历队列 put 到 asynico.queue 里面,再依次 get 出来运行,如果运行结果非 none 就不用再 get 直接退出来
pixcai
2018-07-13 10:23:41 +08:00
官方的 asyncio 已经提供你所需要的 API 了:
asyncio.as_completed(fs, *, loop=None, timeout=None)
Return an iterator whose values, when waited for, are Future instances.

上面提到的 asyncio.wait 会等待所有的执行完,asyncio.as_completed 只要有一个执行完就立即返回,例如你要的效果:
futures = [future1, future2, future3]
for next_completed in asyncio.as_completed(futures):
result = await next_completed
if result is not None:
break
这样在取结果的时候,其它的 future 还在执行,应该就是你要的效果。

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

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

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

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

© 2021 V2EX