抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

异步协程-class01

  • 协程
  • asyncio模块进行异步编程
  • 实战案例

1.协程

协程不是计算机提供,程序员人为创造。
协程(Coroutine),也可以被称为微线程,是一种用户态内的上下文切换的技术,简而言之,其实就是通过一个线程实现代码块相互切换执行。

实现协程的方法:

  • greenlet, 早期模块
  • yield关键字
  • asyncio装饰器(py3.4引入)
  • async、await关键字(py3.5)【推荐】

1.1 greenlet实现协程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from greenlet import greenlet

def func1():
print(1) # 第二步:输出1
  gr2.switch() # 第三步:切换到func2
  print(2) # 第六步:输出2
  gr2.switch() # 第七步:切换到func2

def func2():
print(3) # 第四步:输出3
  gr1.switch() # 第五步:切换到func1
  print(4) # 第八步:输出4
 

gr1 = greenlet(func1)
gr2 = greenlet(func2)

gr1.switch() # 第一步:切换到func1

输出结果

1
2
3
4
1
3
2
4

1.2 yield关键字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def func1():
yield 1
yield from func2()
yield 2


def func2():
yield 3
yield 4


f1 = func1()
for item in f1:
print(item)

输出结果

1
2
3
4
1
3
4
2

1.3 async、await关键字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import asyncio

async def func1():
print(1)
await asyncio.sleep(2)
print(2)

async def func2():
print(3)
await asyncio.sleep(2)
print(4)

tasks = [
asyncio.ensure_future(func1()),
asyncio.ensure_future(func2())
]

loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))

__注意:遇到IO阻塞自动切换
输出结果

1
2
3
4
5
1
3
--------停顿
2
4

协程的意义

在线程中如果遇到IO等待时间,线程可利用空闲时间干其他的事情

2.1 案例:下载三张图片

  • 普通方式
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    import request
    import time

    def download(url):
    name = url.rsplit("/", 1)[1]
    res = requests.get(url)
    with open(name, mode="wb") as f:
    f.write(res.content)
      print(name + "Finish.")

    if "__name__" == "__main__":
    url_list = [
    "https://img-baofun.zhhainiao.com/pcwallpaper_ugc/preview/3760b2031ff41ca0bd80bc7a8a13f7bb_preview.mp4",
    "https://img-baofun.zhhainiao.com/market/97ba6b60662ab4f31ef06cdf5a5f8e94_preview.mp4",
    "https://wallpaperm.cmcm.com/scene/preview_video/750c4e56cb120056c9d155b63025c564_preview.mp4"
    ]
    start = time.time()
    for i in url_list:
    download(i)
    stop = time.time()
    print(stop - start)

  • 协程方式
    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
    import asyncio
    import aiohttp
    import time

    async def download(session, url):
    async with session.get(url) as response:
    content = response.content.read()
    file_name = url.rsplit("/", 1)[1]
    with open(file_name, mode="wb") as f:
    f.write(content)
    print(file_name + " " +"done")

    async def main():
    async with aiohttp.ClientSession as session:
    url_list = [
    "https://img-baofun.zhhainiao.com/pcwallpaper_ugc/preview/3760b2031ff41ca0bd80bc7a8a13f7bb_preview.mp4",
    "https://img-baofun.zhhainiao.com/market/97ba6b60662ab4f31ef06cdf5a5f8e94_preview.mp4",
    "https://wallpaperm.cmcm.com/scene/preview_video/750c4e56cb120056c9d155b63025c564_preview.mp4"
    ]
    taaks = [asyncio.creat_task(download(session, url)) for url in url_list]
    await async.wait(tasks)


    if "__name__" == "__main__":
    start = time.time()
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())
    stop = time.time()
    print(stop - start)
    done

评论