我无法弄清楚这种现象。我正在使用Python 3.6.4。
在这里,我有4个异步功能。在test1
中,我叫asyncio.ensure_future(TestAsync())
并将协程变成一个任务。在其他test2
,test3
,test4
上,我没有打电话给ensure_future()
,我只是创建了协程并将它们传递到列表中,然后将列表传递到事件循环。
我将test1
移出了进入事件循环的列表。因此,我的印象是test1无法运行,但是在我的输出中,它确实可以运行。有人可以向我解释为什么test1
不在事件循环内时仍然输出吗?
import asyncio
import random
async def TestAsync():
print("Test 1 started")
wait = random.randint(1, 10)
await asyncio.sleep(wait)
print("Test 1 done awaited: " + str(wait))
async def TestAsync2():
print("Test 2 started")
wait = random.randint(1, 10)
await asyncio.sleep(wait)
print("Test 2 done awaited: " + str(wait))
async def TestAsync3():
print("Test 3 started")
wait = random.randint(1, 10)
await asyncio.sleep(wait)
print("Test 3 done awaited: " + str(wait))
async def TestAsync4():
print("Test 4 started")
wait = random.randint(1, 10)
await asyncio.sleep(wait)
print("Test 4 done awaited: " + str(wait))
test1 = asyncio.ensure_future(TestAsync())
test2 = TestAsync2()
test3 = TestAsync3()
test4 = TestAsync4()
tasklist = [test2, test3, test4]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasklist))
输出
Test 1 started. <--This is the one wasn't in the event loop
Test 3 started
Test 4 started
Test 2 started
Test 4 done awaited: 1
Test 3 done awaited: 2
Test 1 done awaited: 7
Test 2 done awaited: 10
答案 0 :(得分:1)
正如其他人指出的那样,ensure_future
会将任务添加到默认事件循环中,以在下一次机会运行。 ensure_future
将任意等待转换为asyncio.Future
,在协程对象的情况下,可通过将其包装到Task
(Future
的子类)中来实现,{ 3}}至create_task
。无论调用ensure_future
的代码是否存储对返回的Future的引用,该事件都会在事件循环下次旋转时运行。
要注意的另一重要事项是run_until_complete(x)
的意思是“将x
提交到事件循环并运行循环直到x
完成”,它并不能防止添加任务之前开始运行对run_until_complete
的呼叫。
在Python 3.7中,有一个新函数call,该函数创建一个 new 事件循环并向其提交给定的协程。用asyncio.run_until_complete
替换asyncio.run
会产生您期望的行为。
答案 1 :(得分:0)
答案 2 :(得分:0)
来自docs:
调用协程不会启动其代码运行-调用返回的协程对象在您安排执行时间之前不会做任何事情。有两种基本方法可以启动它运行:从另一个协程调用
await coroutine
或yield from coroutine
(假设另一个协程已经在运行!),或者使用ensure_future()
函数或AbstractEventLoop.create_task()
方法。
正如@dirn's answer所暗示的那样,ensure_future
本身不会启动任务,除非已经运行了事件循环。但是,随后使用run_until_complete
进行的循环启动确实会启动任务。