asyncio相关 - 按key区分任务

  • 作者:KK

  • 发表日期:2020.02.15


应用场景

很多时候我们需要给多个异步任务打一些标记,在执行完后,通过这些标记把它们的值取出来进行判断。


示例代码

下面代码最终还是通过async.gather来执行任务,但是在执行之前先将 tasks 打包成了一个带有标识符的列表。关于这个解决方案我是在 Stack Overflow 上请教来的,大家都研究了直到 python3.7 官方是没有直接的解决方案的,3.8开始有没有就不清楚了。

import asyncio, aiohttp

async def markCallback(key, callback):
	"""用一个key把一个任务标记起来
	"""
	result = None
	try:
		result = await callback
	except BaseException as e:
		result = e

	return key, result


async def gatherDict(tasks: dict, throwException: bool = True):
	"""执行字典形式的任务
	"""
	markedCallbacks = (markCallback(key, callback) for key, callback in tasks.items())
	parallelResult = await asyncio.gather(*markedCallbacks, loop = None, return_exceptions = True)
	
	resultByKeys = {}
	for resultSet in parallelResult:
		taskName, taskResult = resultSet

		if isinstance(taskResult, BaseException):
			if throwException:
				raise taskResult

		resultByKeys[taskName] = taskResult
	return resultByKeys


async def getHtml(url):
	async with aiohttp.ClientSession() as httpSession:
		async with httpSession.get(url) as response:
			return await response.text()


async def main():
	tasks = {
		'html1': getHtml('http://www.kkh86.com/it'),
		'html2': getHtml('http://www.kkh86.com/it/python'),
	}

	result = await gatherDict(tasks) #开始执行,注意这里!!!! 不是  *tasks ,是直接把这个 dict 传进去
	print(
		'请求1的HTML',
		result['html1'][:100],
		'\n\n\n=====================分割线==============================\n\n\n',
		'请求2的HTML',
		result['html2'][:100]
	)


loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()