- 并发任务
- 获取到第一个任务就返回结果
- 给任务命名
- 增加回调函数
- 限制并发数量
- 你可能用了个假异步
- 运行协程的3种机制
- 官方文档
需求:为了达到快速完成同类任务的需要,我们可以使用下列方式进行并发请求,代码如下
import asyncio
# 获取到第一个结果结束并发
async def test(delay_time):
print(f'开始任务{delay_time}')
await asyncio.sleep(delay_time)
return delay_time
async def main():
task_list = [test(i + 2) for i in range(3)]
return await asyncio.gather(*task_list)
ret = asyncio.run(main())
print(ret)
# 参考文档:https://docs.python.org/zh-cn/3/library/asyncio-task.html#running-tasks-concurrently
获取到第一个任务就返回结果
需求:为了速度,并发处理一些任务,但是我们只需要得到其中的一个结果,所以需要在并发任务中当其中的一个任务得到了结果就结束此次并发,并将结果返回,代码如下
import asyncio
# 获取到第一个结果结束并发
async def test(delay_time):
print(f'开始任务{delay_time}')
await asyncio.sleep(delay_time)
return delay_time
task_list = [test(i + 2) for i in range(3)]
done, pending = asyncio.run(asyncio.wait(task_list, return_when=asyncio.FIRST_COMPLETED)) # 第一个任务完成的时候结束
# return await asyncio.wait(task_list, return_when=asyncio.FIRST_EXCEPTION) # 出现第一个错误的时候结束
for task in done:
print(task.result())
for task in pending:
print(task)
# 参考文档:https://docs.python.org/zh-cn/3/library/asyncio-task.html#waiting-primitives
给任务命名
我们还可以给并发的任务命名,通过命名我们可以达到一些预想的结果
- 如下代码
import asyncio
# 获取到第一个结果结束并发
async def test(delay_time):
print(f'开始任务{delay_time}')
await asyncio.sleep(delay_time)
return delay_time
async def main():
task_list = list()
for i in range(3):
task = asyncio.create_task(test(i + 2), name=str(i + 2))
task_list.append(task)
return await asyncio.wait(task_list, return_when=asyncio.FIRST_COMPLETED)
done, pending = asyncio.run(main())
for task in done:
print(task)
print(task.result())
# 可以通过任务的名字获取到一些自己想要得到的信息
# 例如这里:我们就可以通过任务名字获取当初任务传递的参数
print(task.get_name())
增加回调函数
我们还可以给任务添加指定的回调函数,如下代码
import asyncio
# 获取到第一个结果结束并发
async def test(delay_time):
print(f'开始任务{delay_time}')
await asyncio.sleep(delay_time)
return delay_time
# 回调函数
def callback(future):
# 在这里可以写一些我们需要执行的代码
print(f'回调函数:{future.result()}')
async def main():
task_list = list()
for i in range(3):
task = asyncio.create_task(test(i + 2))
# 可以增加回调函数
task.add_done_callback(callback)
task_list.append(task)
return await asyncio.wait(task_list) # 第一个任务完成的时候结束
done, pending = asyncio.run(main())
for task in done:
print(task.result())
限制并发数量
需求:由于硬件的限制,我们需要对资源利用进行控制,也就是根据需求设置程序并发数量,见代码
import asyncio
import time
# # 设置并发数量,需单独实例化,不要放在函数内,否则无效
# sem = asyncio.Semaphore(13)
async def test(delay_time, sem):
# 设置并发数量
async with sem:
print(f'开始任务{delay_time}')
await asyncio.sleep(delay_time)
return delay_time
async def main(sem):
task_list = [test(2, sem) for i in range(10)]
return await asyncio.gather(*task_list)
if __name__ == '__main__':
# 设置并发数量,需单独实例化,不要放在函数内,否则无效
sem = asyncio.Semaphore(2) # 可以在这里设置不同的并发数量测试最后的结果
# 开始计时
start_time = time.time()
ret = asyncio.run(main(sem))
print(ret)
print(f'耗时{time.time() - start_time}')
# 参考文章:https://docs.python.org/zh-cn/3/library/asyncio-sync.html?highlight=semaphore#asyncio.Semaphore
你可能用了个假异步
问题:有很多情况您会发现我明明用了异步,为什么效率没有变化呢?
那是因为您可能用了个假异步(代码错误)
- 对比下列代码执行的结果,你就会发现自己写的代码是不是犯了同样的错误
import asyncio
import time
async def test(delay_time):
print(f'开始任务{delay_time}')
await asyncio.sleep(delay_time)
return delay_time
async def main1():
# 这种方式会造成阻塞,不会进行并发
await test(2)
await test(3)
async def main2():
# asyncio.create_task() 函数用来并发运行作为 asyncio 任务 的多个协程
task1 = asyncio.create_task(test(3))
task2 = asyncio.create_task(test(2))
await task1
await task2
if __name__ == '__main__':
# 开始计时
start_time = time.time()
asyncio.run(main1())
print(f'main1耗时{time.time() - start_time}')
# 开始计时
start_time = time.time()
asyncio.run(main2())
print(f'main2耗时{time.time() - start_time}')
# 参考文章:https://docs.python.org/zh-cn/3/library/asyncio-task.html#creating-tasks
运行协程的3种机制
- 官方说明
- 更多内容
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)