【发布时间】:2018-11-29 22:32:48
【问题描述】:
我试图重现并更好地理解 Cristian Garcia 的 this 博客文章中的 TaskPool 示例,结果遇到了一个非常有趣的结果。
这是我使用的两个脚本。我用随机睡眠呼叫替换了一个实际的网络请求
#task_pool.py
import asyncio
class TaskPool(object):
def __init__(self, workers):
self._semaphore = asyncio.Semaphore(workers)
self._tasks = set()
async def put(self, coro):
await self._semaphore.acquire()
task = asyncio.create_task(coro)
self._tasks.add(task)
task.add_done_callback(self._on_task_done)
def _on_task_done(self, task):
self._tasks.remove(task)
self._semaphore.release()
async def join(self):
await asyncio.gather(*self._tasks)
async def __aenter__(self):
return self
def __aexit__(self, exc_type, exc, tb):
print("aexit triggered")
return self.join()
还有
# main.py
import asyncio
import sys
from task_pool import TaskPool
import random
limit = 3
async def fetch(i):
timereq = random.randrange(5)
print("request: {} start, delay: {}".format(i, timereq))
await asyncio.sleep(timereq)
print("request: {} end".format(i))
return (timereq,i)
async def _main(total_requests):
async with TaskPool(limit) as tasks:
for i in range(total_requests):
await tasks.put(fetch(i))
loop = asyncio.get_event_loop()
loop.run_until_complete(_main(int(sys.argv[1])))
python 3.7.1 上的命令main.py 10 产生以下结果。
request: 0 start, delay: 3
request: 1 start, delay: 3
request: 2 start, delay: 3
request: 0 end
request: 1 end
request: 2 end
request: 3 start, delay: 4
request: 4 start, delay: 1
request: 5 start, delay: 0
request: 5 end
request: 6 start, delay: 1
request: 4 end
request: 6 end
request: 7 start, delay: 1
request: 8 start, delay: 4
request: 7 end
aexit triggered
request: 9 start, delay: 1
request: 9 end
request: 3 end
request: 8 end
根据这个结果,我有几个问题。
- 在上下文管理器退出并触发
__aexit__之前,我不会期望任务运行,因为这是asyncio.gather的唯一触发器。然而,打印语句强烈表明fetch作业甚至在aexit之前发生。到底发生了什么?任务是否正在运行?如果是这样,是什么开始了他们? - 与 (1) 相关。为什么上下文管理器在所有作业返回之前就退出了?
-
fetch作业应该返回一个元组。我怎样才能访问这个值?对于基于 Web 的应用程序,我想开发人员可能希望对网站返回的数据进行操作。
非常感谢任何帮助!
【问题讨论】:
标签: python python-3.x asynchronous python-asyncio aiohttp