当前位置:   article > 正文

【Python】asyncio的使用(async、await关键字)_import asyncio

import asyncio
1.协程

相比于线程和进程,协程显得更加轻量级,因为它是在函数直接进行切换,所以开销更小,也更灵活。之前有介绍过greenlet、gevent这样的协程库(【python】协程(greenlet、gevent)的简单使用),现在再来认识一下Python自带的协程库,asyncio

我们可以使用asyncio创建协程,把同步任务变成异步任务很简单,我们在定义函数的时候在前面加上async修饰,在耗时任务那行代码使用await修饰,这时候调用函数,它就会返回一个协程(coroutine)对象,然后调用asyncio.run()把协程对象丢进去就能执行了

import asyncio
import time


async def test(i, n):
    print(f"任务{i}将休眠{n}秒")
    await asyncio.sleep(n)
    print(f"任务{i}{n}秒后继续执行")


start_time = time.time()
asyncio.run(test(1, 1))
print(f'总用时{time.time() - start_time}秒')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

执行输出如下

任务1将休眠1秒
任务1在1秒后继续执行
总用时1.0107183456420898秒
  • 1
  • 2
  • 3
2.使用asyncio执行多任务
2.1 同步执行

假设有一个任务test(),需要执行三次,每次分别休眠2秒、1秒、3秒,如果是同步执行,一共需要耗时6秒

import time


def test(i, n):
    print(f"任务{i}将休眠{n}秒")
    time.sleep(n)
    print(f"任务{i}{n}秒后继续执行")


start_time = time.time()
task_list = [test(1, 2), test(2, 1), test(3, 3)]
print(f'总用时{time.time() - start_time}秒')

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

执行输出如下

任务1将休眠2秒
任务1在2秒后继续执行
任务2将休眠1秒
任务2在1秒后继续执行
任务3将休眠3秒
任务3在3秒后继续执行
总用时6.022886514663696秒
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
2.2 异步执行

我们使用asyncio把上面的多任务改成异步执行,就是使用async和await修饰一下。在调用执行的时候,需要创建一个事件循环,在事件循环里执行任务,这样它会在耗时的时候自动切换到其他任务。另外,最后要记得关闭事件循环。具体写法如下

import asyncio
import time


async def test(i, n):
    print(f"任务{i}将休眠{n}秒")
    await asyncio.sleep(n)
    print(f"任务{i}{n}秒后继续执行")


start_time = time.time()

task_list = [test(1, 2), test(2, 1), test(3, 3)]
loop = asyncio.get_event_loop()
try:
    loop.run_until_complete(asyncio.wait(task_list))
finally:
    loop.close()
print(f'总用时{time.time() - start_time}秒')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

执行输出如下

任务2将休眠1秒
任务3将休眠3秒
任务1将休眠2秒
任务2在1秒后继续执行
任务1在2秒后继续执行
任务3在3秒后继续执行
总用时2.9994614124298096秒
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

同步执行的时候需要6秒,改为异步执行需要3秒就行了

换一种写法。执行某个

import asyncio
import time


async def test_job(i):
    print(f"任务 {i} 开始")
    await asyncio.sleep(1)
    print(f"任务 {i} 结束")


async def run_main():
    task_list = [test_job(i) for i in range(101)]
    batch_size = 10
    for i in range(0, len(task_list), batch_size):
        batch_tasks = task_list[i: i + batch_size]
        await asyncio.gather(*batch_tasks)


start_time = time.time()
asyncio.run(run_main())
print(f"总耗时: {time.time() - start_time}")

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
2.3 异步执行的返回值

如果想要得到异步任务的返回值,只需要使用asyncio.ensure_future()函数把任务包装成一个Task对象,执行完之后再调用它的result()方法就能得到返回值了

import asyncio
import time


async def test(i, n):
    print(f"任务{i}将休眠{n}秒")
    await asyncio.sleep(n)
    print(f"任务{i}{n}秒后继续执行")
    return f"任务{i}执行{n}秒后结束"


start_time = time.time()
task_list = [asyncio.ensure_future(test(1, 2)),
             asyncio.ensure_future(test(2, 1)),
             asyncio.ensure_future(test(3, 3))]
loop = asyncio.get_event_loop()
try:
    loop.run_until_complete(asyncio.wait(task_list))
finally:
    loop.close()
task_result = [task.result() for task in task_list]
print(f"task_result: {task_result}")
print(f'总用时{time.time() - start_time}秒')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

执行输出如下

任务1将休眠2秒
任务2将休眠1秒
任务3将休眠3秒
任务2在1秒后继续执行
任务1在2秒后继续执行
任务3在3秒后继续执行
task_result: ['任务1执行2秒后结束', '任务2执行1秒后结束', '任务3执行3秒后结束']
总用时3.0089805126190186秒
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
3.举例:异步下载图片

如果是一张一张按顺序下载图片,我这里大概需要一分多钟下载完39张图片,改为asyncio异步下载大概需要三四秒。

注意,发起异步网络请求不能使用requests,因为它是同步的,而应该aiohttp或httpx,我这里使用的是aiohttp

import asyncio
import os.path
import time

import aiohttp
import requests


def get_img_url():
    img_url_list = list()
    res = requests.get("https://game.gtimg.cn/images/lol/act/img/js/hero/1.js").json()

    for skin in res.get("skins"):
        if skin["mainImg"]:
            img_url_list.append(skin["mainImg"])
        elif skin["iconImg"]:
            img_url_list.append(skin["iconImg"])
        elif skin["sourceImg"]:
            img_url_list.append(skin["sourceImg"])
        elif skin["chromaImg"]:
            img_url_list.append(skin["chromaImg"])
    return img_url_list


async def download_img(img_url):
    save_path = "./图片"
    if not os.path.exists(save_path):
        os.mkdir(save_path)
    name = os.path.split(img_url)[1]
    async with aiohttp.ClientSession() as session:
        async with session.get(img_url) as res:
            with open(os.path.join(save_path, name), "wb") as f:
                f.write(await res.content.read())


if __name__ == '__main__':
    url_list = get_img_url()
    print(len(url_list), url_list)
    start_time = time.time()
    task_list = [download_img(url) for url in url_list]
    loop = asyncio.get_event_loop()
    loop.run_until_complete(asyncio.wait(task_list))
    print("spent_time:", time.time() - start_time)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/703694
推荐阅读
相关标签
  

闽ICP备14008679号