1
我有一个关于python的asyncio
模块中的事件循环如何管理未完成任务的问题。请看下面的代码:Python asyncio任务排序
import asyncio
@asyncio.coroutine
def a():
for i in range(0, 3):
print('a.' + str(i))
yield
@asyncio.coroutine
def b():
for i in range(0, 3):
print('b.' + str(i))
yield
@asyncio.coroutine
def c():
for i in range(0, 3):
print('c.' + str(i))
yield
tasks = [
asyncio.Task(a()),
asyncio.Task(b()),
asyncio.Task(c()),
]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait([t1, t2, t3]))
运行,这将打印:
a.0
b.0
c.0
a.1
b.1
c.1
a.2
b.2
c.2
注意,它总是打印出 '一',那么 'B',那么 'C'。我猜测无论每个协程经过多少次迭代,它总是按照这个顺序打印。所以你永远不会看到类似
b.100
c.100
a.100
从node.js的背景的,这告诉我,事件循环这里是内部保持一个队列,使用它来决定下一步运行哪一个任务。它最初将a()
放在队列的前面,然后b()
,然后c()
,因为这是列表中任务的顺序传递给asyncio.wait()
。然后,只要它碰到yield语句,它就会将该任务放在队列的末尾。我想在一个更现实的例子中,假设你正在做一个异步http请求,它会在http响应返回后将a()
放回队列末尾。
我可以得到这个阿门吗?
对,它会尽快运行回调,因此如果I/O花费不同的时间来完成它们将开始出现故障。我的观点是,如果没有I/O进行(如我的例子),由于对幕后的任务(可能是队列)进行某种管理,它们总是以可预测的顺序运行。而不像线程那样会根据操作系统线程调度器运行它们,并且是不可预测的。 – d512
如果没有I/O,请勿使用asyncio。它们是不可预测的,你不能确定它将如何在不同的实现或版本中或在不同的条件下工作。 – Udi
我很欣赏这种回应,但我的问题不是关于'asyncio'的适当使用,而是它如何实现。当然,对图书馆实施细节做出假设是不安全的,而且我并没有试图暗示以其他方式提出这个问题。只是想看看有没有人知道它是如何工作的。 – d512