python asyncio -- 异步编程 python异步编程用在哪里

liftword22小时前技术文章4

概念:

asyncio 是 python3.4 版本引入的标准库,直接内置了对异步IO的支持。本质上asyncio的编程模型是一个消息循环,asyncio 模块内部实现了EventLoop,把需要执行的协程扔到EventLoop 中执行,就实现了异步IO。


首先注意几个概念:

coroutine: 协程,通过async定义的方法就是一个coroutine,当我们定义一个coroutine的时候,并不会执行它,只有当这个coroutine被转换为task,并且注册到event loop里面时候,才有可能被event loop调用执行。

event loop:事件循环,会不断地检测每个task的状态,当某个task可以被执行的时候,就会执行这个任务,直到这个任务结束或者这个任务遇到一个新的await 标记的新的coroutine。

task:coroutine 需要被转换成task,才可以被执行。

await:作用是将目前代码执行权交还给event loop,并且向event loop 注册一个新的coroutine。

案例:

import asyncio
import time

async def say_after(delay,what):
    await asyncio.sleep(delay)
    return f"{what} -- {delay}"

async def main():
    ret = await asyncio.gather(say_after(1,"hello"),say_after(2,"world"))
    print("finished)

asyncio.run(main())

分析例子的执行过程:

--1 main 函数被定义为一个coroutine,并通过asyncio.run 执行,这里包含了coroutine转成task的过程

--2 asyncio.gather 将两个coroutine转成task,并且注册到event loop 内

--3 await 告诉event loop 我有两个task需要执行,执行完之后才能接着执行当前的coroutine

--4 此时event loop 内部有main 和 hello world 三个task,并且main 需要等待hello 和 world 执行完

--5 执行hello 遇到sleep coroutine,交还控制权,并且注册了sleep 这个task,此时有4个task

--6 hello sleep task 任务状态等待跳过,执行world task 这个任务,同理遇到sleep coroutine,注册交还控制权

--7 此时有5个task: main -- hello --hello_sleep -- world -- world_sleep,并且main需要等hello world,hello和world需要分别等各自的sleep。event loop 就会在两个sleep task 之间来回检测,直到有任务结束,然后逐层退出,从表面看起来两个sleep是同时执行的。

我们也可以显示地创建task,然后再让他们await住:

import time
import asyncio

async def task1():
    print("Starting task 1")
    await asyncio.sleep(1)
    print("task 1 finished")
    
async def task2():
    print("Starting task 2")
    await asyncio.sleep(2)
    print("task 2 finished")
    
async def task3():
    print("Starting task 3")
    await asyncio.sleep(3)
    print("task 3 finished")

if __name__ == "__main__":
    async def main():
        startTime = time.time()
        tasks = [asyncio.create_task(task1()), asyncio.create_task(task2()), asyncio.create_task(task3())]
        for task in tasks:
            await task        
        print("Total time: ",time.time() - startTime)
    asyncio.run(main())

再附上一个网络请求的例子:

import asyncio

async def wget(host):
    print(f"wget {host}...")
    # 连接80端口:
    reader, writer = await asyncio.open_connection(host, 80)
    # 发送HTTP请求:
    header = f"GET / HTTP/1.0\r\nHost: {host}\r\n\r\n"
    writer.write(header.encode("utf-8"))
    await writer.drain()

    # 读取HTTP响应:
    while True:
        line = await reader.readline()
        if line == b"\r\n":
            break
        print("%s header > %s" % (host, line.decode("utf-8").rstrip()))
    # Ignore the body, close the socket
    writer.close()
    await writer.wait_closed()
    print(f"Done {host}.")

async def main():
    await asyncio.gather(wget("www.sina.com.cn"), wget("www.sohu.com"), wget("www.163.com"))

asyncio.run(main())

await writer.drain() 和 await writer.wait_closed() 都是异步的,因此几个task之间可以并发地去等待,起到加速的作用。

总结:

--1 asyncio 只有一个线程,因此不需要锁的机制,只有在函数内部有异步调用的时候才有效果

--2 asyncio 内部是一个event loop 循环检测任务状态,执行可以被执行的任务

--3 某个任务在执行中切换到其他任务的方式有两种,一种是任务结束了,一种显示地调用await交还控制权

相关文章

人生苦短,我要在VSCode里面用Python

轻沉 发自 浅度寺 量子位 出品 | 公众号 QbitAI在程序员圈子里,Visual Studio Code(以下简称VSCode)可以说是目前最火的代码编辑器之一了。它是微软出品的一款可扩展的轻量...

Python启航:30天编程速成之旅(第26天)- pathlib

喜欢的条友记得关注、点赞、转发、收藏,你们的支持就是我最大的动力源泉。前期基础教程:「Python3.11.0」手把手教你安装最新版Python运行环境讲讲Python环境使用Pip命令快速下载各类库...

轻松教会你Python的文件操作 python文件操作的三个步骤

1、前言Python中有几个内置模块和方法来处理文件。这些方法被分割到例如os, os.path , shutil 和 pathlib 等等几个模块中。文章将列举Python中对文件最常用的操作和方法...

你不可不知的Python宝藏库:pathlib.Path

在日常的Python开发中,我们经常需要处理文件和路径。传统上,我们可能会使用os模块来完成这些任务,但实际上,有一个更为优雅和强大的工具——pathlib模块,特别是其中的Path类,正是我们今天要...

Python Supervisor进程管理介绍(大厂也在用)

要了解Supervisor进程管理需要先了解什么是守护进程。守护进程(daemon)是一类在后台运行的特殊进程,用于执行特定的系统任务。很多守护进程在系统引导的时候启动,并且一直运行直到系统关闭。另一...