协程理论

协程

(1)介绍

  • 什么是协程?

    • 就是在线程下面开设多线程
  • 协程(Coroutines)是一种用于异步编程的概念,它是一种更轻量级的线程。协程允许程序在执行过程中暂停和恢复,从而实现非阻塞的异步编程模型

    在 Python 中,协程可以使用 asyncio 模块来实现。Python 3.5 引入了 asyncawait 关键字,使得定义和调用协程更加方便

  • 协程的优点:

  1. 协程的切换开销更小,属于程序级别的切换,操作系统完全感知不到,因而更加轻量级
  2. 单线程内就可以实现并发的效果,最大限度地利用cpu
  3. 应用程序级别速度要远远高于操作系统的切换
  • 协程的缺点:
  1. 协程的本质是单线程下,无法利用多核,可以是一个程序开启多个进程,每个进程内开启多个线程,每个线程内开启协程
  2. 协程指的是单个线程,因而一旦协程出现阻塞,将会阻塞整个线程(多个任务一旦有一个阻塞没有切,整个线程都阻塞在原地,该线程内的其他的任务都不能执行了)
  • 总结:
  1. 必须在只有一个单线程里实现并发
  2. 修改共享数据不需加锁
  3. 用户程序里自己保存多个控制流的上下文栈
  4. 附加:一个协程遇到IO操作自动切换到其它协程(如何实现检测IO,yield、greenlet都无法实现,就用到了gevent模块(select机制))

(2)greenlet模块

  • greenlet 是一个用于实现协程的 Python 库,它允许在程序中创建轻量级的用户级线程,这些线程被称为 "greenlet"。每个 greenlet 都有自己的执行状态,但它们共享相同的全局解释器(GIL),因此只有一个 greenlet 能够执行 Python 代码。
from greenlet import greenlet

def foo():
    print("foo start")
    gr2.switch()
    print("foo end")
    gr2.switch()

def bar():
    print("bar start")
    gr1.switch()
    print("bar end")

gr1 = greenlet(foo)
gr2 = greenlet(bar)

gr1.switch()

# foo start
# bar start
# foo end
# bar end

(3)asyncio模块

  • asyncio 是 Python 标准库提供的一个用于编写异步代码的模块,它提供了一种基于事件循环的异步编程模型。通过 asyncio,可以轻松编写高效的异步 I/O 代码,处理大量的并发连接和事件。

  • 以下是 asyncio 的主要特点和用法:

  1. 事件循环(Event Loop)asyncio 基于事件循环的模型,其中一个主要的事件循环负责调度和执行异步任务。
  2. 协程(Coroutines)asyncio 使用 async defawait 关键字来定义协程,协程是一种轻量级的并发执行单元,可以在异步程序中方便地实现并发操作。
  3. 异步 I/Oasyncio 提供了异步的 I/O 操作,包括文件读写、网络通信等,可以有效地处理大量的 I/O 请求。
  4. 并发任务asyncio 支持并发执行多个任务,通过 asyncio.gather()asyncio.wait() 等函数可以同时执行多个协程任务。
  5. 异步上下文管理器asyncio 提供了异步上下文管理器,例如 async with 语法,用于管理异步资源的生命周期。
  6. 异步事件处理asyncio 可以处理异步事件,例如定时器、信号等,以及与外部事件循环的集成。

(4)协程函数

  • 协程函数是指使用了 async def 声明的函数,它们允许在函数内部使用 await 关键字来暂停函数的执行,等待异步操作的完成,然后在操作完成后继续执行。在 Python 中,协程函数通常用于异步编程,通过 asyncio 模块来实现。
async def heart():
    pass
  • 以下是协程函数的一些特点和用法:
  1. 使用 async def 定义:协程函数使用 async def 关键字来定义,例如 async def heart():
  2. 支持 await 关键字:协程函数内部可以使用 await 关键字来暂停函数的执行,等待异步操作的完成,例如 await asyncio.sleep(1)
  3. 异步执行:协程函数是异步执行的,它们可以在一个事件循环中被调度和执行,而不会阻塞程序的其他部分。
  4. 协程链:协程函数可以相互调用,并形成协程链,其中一个协程函数可以在等待另一个协程函数完成时暂停执行。
  5. 与异步上下文管理器一起使用:协程函数可以与异步上下文管理器一起使用,例如 async with,用于管理异步资源的生命周期。

(5)协程对象

  • 协程对象是通过协程函数调用而创建的对象,它表示了一个可等待的异步操作。在 Python 中,协程对象通常是使用 async def 关键字定义的协程函数所返回的。这些对象可以被用于构建异步程序,参与事件循环的调度,以及与其他协程进行协作。
async def heart():
    pass


res = heart()
print(res)  # <coroutine object heart at 0x000001AD87304350>
  • 以下是协程对象的一些特点和用法:
  1. 通过协程函数创建:协程对象是通过调用使用 async def 定义的协程函数而创建的,例如 coro = heart()
  2. 可等待对象:协程对象是可等待对象的一种,它可以被 await 关键字用于暂停当前协程的执行,等待其完成,例如 await coro
  3. 异步调度:协程对象可以被调度到事件循环中执行,它们可以在事件循环中被等待、调度和执行。
  4. 状态:协程对象具有不同的状态,包括未启动(pending)、已运行(running)、已完成(done)等状态。
  5. 返回值:协程对象可以返回一个值,这个值可以在协程执行完成后通过 coro.result() 或者 await coro 获取。

(6)基本应用

  • 执行协程代码的方式一:
import asyncio

async def heart():
    print(f'这是协程函数')

def main_asy():
    res = heart()
    pool =  asyncio.get_event_loop()
    pool.run_until_complete(res)

if __name__ == '__main__':
    main_asy()
  • 执行协程代码的方式二:
import asyncio

async def heart():
    print(f'这是协程函数')

def main_async():
    res = heart()
    asyncio.run(res)

if __name__ == '__main__':
    main_async() # 这是协程函数

(7)await关键字

  • await表示当前任务遇到阻塞需要切换

  • await 关键字是用于异步编程中的协程中的一种语法,它通常与协程对象一起使用,用于暂停当前协程的执行,等待另一个协程执行完成,并获取其结果。

  • 在 Python 中,当使用 await 关键字时,Python 解释器会暂停当前协程的执行,将控制权返回给事件循环,直到等待的协程执行完成并返回结果。一旦等待的协程完成,await 表达式将返回结果,并继续执行当前协程的后续代码。

  • 以下是 await 关键字的一些特点和用法:

  1. 用于异步上下文中await 关键字只能在异步上下文中使用,例如在异步函数(使用 async def 定义的函数)或者异步上下文管理器中。
  2. 等待协程对象await 后面通常跟着一个协程对象,用于等待该协程执行完成,并获取其返回值。
  3. 暂停当前协程的执行await 表达式会暂停当前协程的执行,将控制权交给事件循环,直到等待的协程执行完成。
  4. 获取协程返回值:一旦等待的协程完成,await 表达式将返回协程的返回值,可以将其赋值给变量或直接在表达式中使用。
  5. 非阻塞:与传统的同步编程中的阻塞调用不同,await 关键字不会阻塞程序的执行,而是在等待异步操作完成时允许其他协程继续执行。
import asyncio


async def my_coroutine():
    print("协程开始执行")  # 打印协程开始执行的消息
    await asyncio.sleep(1)  # 等待1秒钟
    print("协程执行完成")  # 打印协程执行完成的消息
    return "来自协程的问候"  # 返回一个字符串


async def main():
    print("主函数开始执行")  # 打印主函数开始执行的消息
    result = await my_coroutine()  # 等待协程执行完成,并获取返回值
    print("协程返回结果:", result)  # 打印协程返回的结果
    print("主函数执行完成")  # 打印主函数执行完成的消息


asyncio.run(main())  # 运行主函数
# 主函数开始执行
# 协程开始执行
# 协程执行完成
# 协程返回结果: 来自协程的问候
# 主函数执行完成

(8)Task对象

  • asyncio.Task 对象是 asyncio 模块中用于表示协程任务的类。它代表了一个异步操作,可以在事件循环中被调度和执行。asyncio.Task 对象与协程函数之间是一种桥梁,它允许你在事件循环中管理和调度协程的执行。
  • 以下是 asyncio.Task 对象的一些特点和用法:
  1. 创建任务:使用 asyncio.create_task() 函数或 loop.create_task() 方法来创建一个 asyncio.Task 对象,将一个协程函数包装成一个任务。
  2. 任务状态asyncio.Task 对象具有不同的状态,包括待运行(pending)、运行中(running)、已完成(done)等状态,可以通过 task.status() 方法来获取任务的状态。
  3. 取消任务:可以通过调用 task.cancel() 方法来取消任务的执行,取消后任务的状态将变为已取消(cancelled),并触发相应的取消异常。
  4. 等待任务完成:可以使用 await task 语法或 task.result() 方法来等待任务完成,并获取任务的结果。
  5. 异常处理:可以通过 task.exception() 方法来获取任务执行过程中的异常信息,并进行相应的处理。
import asyncio


async def my_coroutine():
    print("协程开始执行")
    await asyncio.sleep(1)
    print("协程执行完成")
    return "来自协程的问候"


async def main():
    print("主函数开始执行")
    task = asyncio.create_task(my_coroutine())  # 创建一个任务
    print("任务对象:", task)
    result = await task  # 等待任务执行完成,并获取返回值
    print("任务返回结果:", result)
    print("主函数执行完成")


asyncio.run(main())  # 运行主函数

# 主函数开始执行
# 任务对象: <Task pending name='Task-2' coro=<my_coroutine() running at D:\2023propygo\test.py:8>>
# 协程开始执行
# 协程执行完成
# 任务返回结果: 来自协程的问候
# 主函数执行完成

(9)aiohttp对象

  • 功能aiohttp 允许您编写异步的 HTTP 客户端和服务器,它基于 Python 的 asyncio 模块,提供了高效的异步 I/O 操作。

  • 用途:您可以使用 aiohttp 构建异步的 Web 服务器、Web 客户端、REST API、HTTP 代理等。

  • 特点

    • 异步支持:aiohttp 提供了异步的 HTTP 客户端和服务器,可以处理大量并发连接。
    • 高性能:由于使用了异步 I/O 操作,aiohttp 能够充分利用系统资源,提供高性能的网络通信。
    • 简单易用:aiohttp 提供了简洁的 API,易于学习和使用,同时提供了丰富的文档和示例。
  • aiohttp 模块提供了几种重要的对象,用于构建异步的 HTTP 客户端和服务器。以下是其中一些常用的对象:

  1. aiohttp.ClientSession
    • ClientSession 是用于发送 HTTP 请求的异步客户端会话对象。
    • 您可以使用它创建和发送 HTTP 请求,并管理请求的状态和连接池。
    • 它提供了多种方法来发送 GET、POST 等类型的请求,并支持异步操作。
  2. aiohttp.ClientResponse
    • ClientResponse 是客户端接收到的 HTTP 响应对象。
    • 当使用 ClientSession 发送请求时,会得到一个 ClientResponse 对象作为响应。
    • 它包含了响应的状态码、头部信息、内容等,并提供了多种方法来读取和处理响应内容。
  3. aiohttp.ClientRequest
    • ClientRequest 是客户端发送的 HTTP 请求对象。
    • 当使用 ClientSession 发送请求时,会创建一个 ClientRequest 对象表示待发送的请求。
    • 您可以在创建请求对象时设置请求的 URL、方法、头部、数据等信息,并将其传递给 ClientSession 进行发送。
  4. aiohttp.web.Application
    • Application 是用于构建异步 Web 服务器的应用程序对象。
    • 您可以创建一个 Application 对象来定义路由、中间件、处理程序等,并将其运行在 aiohttp.web.run_app() 函数中。
  5. aiohttp.web.Requestaiohttp.web.Response**:
    • 这两个对象是用于处理 HTTP 请求和响应的对象,在编写 aiohttp 的 Web 服务器时经常会使用到。
    • Request 对象表示客户端发送的 HTTP 请求,Response 对象表示服务器返回的 HTTP 响应。
  • 这些对象是 aiohttp 中的核心组件,可以根据自己的需求使用它们来构建异步的 HTTP 客户端或服务器。

  • 模版:

import aiohttp
import asyncio

async def main():
    async with aiohttp.ClientSession() as session:
        async with session.get('http://httpbin.org/headers') as response:
            print(await response.text())

asyncio.run(main())
posted @ 2024-02-14 23:14  ssrheart  阅读(3)  评论(0编辑  收藏  举报