python asyncio.create_task 任务比预期提前退出?
python asyncio.create_task tasks exiting earlier than expected?
我有以下代码:
import asyncio
async def myfunc(i):
print("hello", i)
await asyncio.sleep(i)
print("world", i)
async def main():
asyncio.create_task(myfunc(2))
asyncio.create_task(myfunc(1))
asyncio.run(main())
它输出:
hello 2
hello 1
请注意,world
并未在任何地方打印。为什么会产生我们看到的输出?我期待:
hello 2
hello 1
world 1
world 2
因为我认为 asyncio.sleep(i)
调用会将执行交给事件循环,此时事件循环会在它们各自的等待时间后重新安排它们。显然我误会了。有人可以解释一下吗?
问题是 main 中的循环没有等待任务完成导致任务没有完成执行。使用 asyncio.gather()
启动并等待所有协程执行。
import asyncio
async def myfunc(i):
print("hello", i)
await asyncio.sleep(i)
print("world", i)
async def main():
await asyncio.gather(myfunc(2), myfunc(1))
asyncio.run(main())
你在评论中描述的逻辑比较复杂,没有实现它的功能,所以你必须设计逻辑,在这种情况下,必须满足2个条件才能完成应用程序:
- 必须启动所有任务。
- 应该没有活动任务。
考虑到这一点,我使用 Future 创建一个标志来指示它,还使用 add_done_callback 通知我作业已完成。
import asyncio
from collections import deque
import random
async def f(identifier, seconds):
print(f"Starting task: {identifier}, seconds: {seconds}s")
await asyncio.sleep(seconds)
print(f"Finished task: {identifier}")
return identifier
T = 3
class Manager:
def __init__(self, q):
self._q = q
self._future = asyncio.get_event_loop().create_future()
self._active_tasks = set()
self._status = False
@property
def q(self):
return self._q
def launch_task(self):
try:
identifier = self.q.pop()
except IndexError:
return False
else:
seconds = random.uniform(T - 1, T + 1)
task = asyncio.create_task(f(identifier, seconds))
self._active_tasks.add(identifier)
task.add_done_callback(self._finished_callback)
return True
async def work(self):
self._status = True
while self.launch_task():
await asyncio.sleep(T)
self._status = False
await self._future
def _finished_callback(self, c):
self._active_tasks.remove(c.result())
if not self._active_tasks and not self._status:
self._future.set_result(None)
async def main():
identifiers = deque(range(10))
manager = Manager(identifiers)
await manager.work()
if __name__ == "__main__":
asyncio.run(main())
找到了比@eyllanesc 提供的解决方案简单得多的解决方案。原来有一个实现它的函数
我有以下代码:
import asyncio
async def myfunc(i):
print("hello", i)
await asyncio.sleep(i)
print("world", i)
async def main():
asyncio.create_task(myfunc(2))
asyncio.create_task(myfunc(1))
asyncio.run(main())
它输出:
hello 2
hello 1
请注意,world
并未在任何地方打印。为什么会产生我们看到的输出?我期待:
hello 2
hello 1
world 1
world 2
因为我认为 asyncio.sleep(i)
调用会将执行交给事件循环,此时事件循环会在它们各自的等待时间后重新安排它们。显然我误会了。有人可以解释一下吗?
问题是 main 中的循环没有等待任务完成导致任务没有完成执行。使用 asyncio.gather()
启动并等待所有协程执行。
import asyncio
async def myfunc(i):
print("hello", i)
await asyncio.sleep(i)
print("world", i)
async def main():
await asyncio.gather(myfunc(2), myfunc(1))
asyncio.run(main())
你在评论中描述的逻辑比较复杂,没有实现它的功能,所以你必须设计逻辑,在这种情况下,必须满足2个条件才能完成应用程序:
- 必须启动所有任务。
- 应该没有活动任务。
考虑到这一点,我使用 Future 创建一个标志来指示它,还使用 add_done_callback 通知我作业已完成。
import asyncio
from collections import deque
import random
async def f(identifier, seconds):
print(f"Starting task: {identifier}, seconds: {seconds}s")
await asyncio.sleep(seconds)
print(f"Finished task: {identifier}")
return identifier
T = 3
class Manager:
def __init__(self, q):
self._q = q
self._future = asyncio.get_event_loop().create_future()
self._active_tasks = set()
self._status = False
@property
def q(self):
return self._q
def launch_task(self):
try:
identifier = self.q.pop()
except IndexError:
return False
else:
seconds = random.uniform(T - 1, T + 1)
task = asyncio.create_task(f(identifier, seconds))
self._active_tasks.add(identifier)
task.add_done_callback(self._finished_callback)
return True
async def work(self):
self._status = True
while self.launch_task():
await asyncio.sleep(T)
self._status = False
await self._future
def _finished_callback(self, c):
self._active_tasks.remove(c.result())
if not self._active_tasks and not self._status:
self._future.set_result(None)
async def main():
identifiers = deque(range(10))
manager = Manager(identifiers)
await manager.work()
if __name__ == "__main__":
asyncio.run(main())
找到了比@eyllanesc