首页 > 其他分享 >协程理论

协程理论

时间:2024-02-14 23:25:32浏览次数:32  
标签:异步 协程 理论 await async 执行 asyncio

协程

(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())

标签:异步,协程,理论,await,async,执行,asyncio
From: https://www.cnblogs.com/ssrheart/p/18015833

相关文章

  • 体光伏效应和二次谐波产生的微观理论(Photogalvanic effect 、bulk photovoltaic effec
    此领域较易入门,经典文献为:1.综述:https://www.nature.com/articles/s41563-021-00992-72.Sipe大佬的论文:开创领域的两篇最经典论文,值得全部重复:https://journals.aps.org/prb/abstract/10.1103/PhysRevB.61.5337https://journals.aps.org/prb/abstract/10.1103/PhysRevB.52.146......
  • 我在代码随想录|写代码| 贪心算法 | 理论基础, 455.分发饼干, 376. 摆动序列,53. 最大
    学习目标:博主介绍:27dCnc专题:数据结构帮助小白快速入门......
  • Unity Coroutine 协程概述
    协程技术是将一个方法切分到不同帧上执行的技术,但是他和多线程有本质区别,多线程技术是利用CPU物理核心实现同时运行多个方法(程序)的技术,而协程只是让一个方法能够被我们拆分为多个部分,让每个部分在我们规定的时刻执行,看起来就好像同时在执行几个方法一样。简单而言,协程技术就是将方......
  • 大白话说明白K8S的PV / PVC / StorageClass(理论+实践)
    本文主要通过大白话说明白PV、PVC的概念和原理,再说说StorageClass的作用,最后通过实践加深理解。先来个一句话总结:PV、PVC是K8S用来做存储管理的资源对象,它们让存储资源的使用变得可控,从而保障系统的稳定性、可靠性。StorageClass则是为了减少人工的工作量而去自动化创建PV的组......
  • 5分钟搞懂K8S的污点和容忍度(理论+实战)
    本文主要快速讲解Kubernetes的污点和容忍度,一句话总结:如果Pod能容忍某个节点上的污点,那么Pod就可以调度到该节点。在K8S中,如果Pod能容忍某个节点上的污点,那么Pod就可以调度到该节点。如果不能容忍,那就无法调度到该节点。污点和容忍度就像谈恋爱的小情侣,你情我愿,女生知道男生的......
  • 各种bin在多种情况下漏洞利用的理论和实践
    先看一下main_arena中的大致结构:largebinattck此图不完全正确,其中largebin里的chunk如果是小组中最前面的那个chunk,并且大组中只有一个小组,bk_nextsize和fd_nextsize就都指向自己,且链表当中最后一个chunk的bk和最前面的chunk的fd指针指向头部,如果是小组中非最前面的chunk,则b......
  • 协程概览
    目录什么是协程协程的优缺点:协程的分类对称协程与⾮对称协程有栈协程与⽆栈协程什么是协程我们可以简单的认为:协程就是用户态的线程,但是上下文切换的时机是靠调用方(写代码的开发人员)自身去控制的;同时,协程和用户态线程非常接近,用户态线程之间的切换不需要陷入内核,但部分操作系统......
  • 编译原理论述
    编译程序工作的几个阶段包括:词法分析(LexicalAnalysis):也称为扫描(Scanning)或词法扫描(LexicalScanning)。这个阶段的任务是从左到右一个字符一个字符地读入源程序,将其划分成一系列的记号(token)。每个记号由两部分组成,一个是记号本身,一个是记号的属性值(比如关键字、变量名、常量值、......
  • (14/60)二叉树理论基础、递归遍历、迭代遍历、统一迭代
    二叉树理论基础分类满二叉树:只有度为0和度为2的结点,且度为0结点在同一层上(每一层的结点都是满的)。完全二叉树:除了底层外其他层结点都是满的(底层当然也可以是满的),且底层结点从左往右连续不断。二叉搜索树:树的每个结点满足:左子树所有结点值均小于根结点的值右子树所有......
  • 代码随想录算法训练营第十四天| 理论基础 递归遍历 迭代遍历 统一迭代
    理论基础代码随想录(programmercarl.com)二叉树的链接形式定义(防忘)structTreeNode{intval;TreeNode*left;TreeNode*right;TreeNode(intx):val(x),left(NULL),right(NULL){}};额外补充(关于unordered_map和map)unordered_map和map类似,都是存储......