python中的协程(coroutine)

2024-01-28 04:58
文章标签 python 协程 coroutine

本文主要是介绍python中的协程(coroutine),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1. asyncio库

1.1 事件循环

事件循环是asyncio提供的核心运行机制。

1.2 协程

  • 协程不是线程,也不是进程,它是用户 空间调度的完成并发处理的方式
  • 线程、进程是由操作系统调度,而协程是线程内完成调度,它不需要更多的线程,自然也没有多线程切换带类的开销
  • 协程是非抢占式调度,只有一个协程主动让出控制权,另一个协程才会被调度
  • 协程也不需要使用锁机制,因为是在同一个线程中
  • 多CPU下,可以使用多进程和协程配合,既能进程并发又能发挥协程在单线程中的优势
  • python中的协程是基于生成器的
  • asyncio.iscoroutine(obj)判断是不是协程对象
  • ayncio.iscoroutinefunction(func)判断是不是协程函数

1.2.1 future

和concurrent.futures.Future类似,通过Future对象可以了解任务执行的状态数据。事件循环来监控Future对象是否完成。

1.2.2 task

Task类是Tuture类的子类,它的作用就是把协程包装成一个Future对象。

1.2.3 协程的使用

import asyncio@asyncio.coroutine
def a():for i in range(3):print('a.x', i)yieldreturn 'a() return 1000'@asyncio.coroutine
def b():for i in 'abcdefg':print('b.x', i)yieldreturn 'b() return 2000'# x = a()
# y = b()
# print(asyncio.iscoroutinefunction(a))
# print(asyncio.iscoroutine(x))
#
# for j in range(3):  # 循环,生成器函数
#     next(x)
#     next(y)loop = asyncio.get_event_loop()  # 大循环def cb(fut):print(fut.result())ts = []
for x in (a(), b()):t = asyncio.ensure_future(x)t.add_done_callback(cb)ts.append(t)task1 = loop.create_task(a())
task2 = loop.create_task(b())# wait 迭代所有的coroutine对象,将他们封装成一个future对象
# loop.run_until_complete(asyncio.wait((task1, task2)))
ret = loop.run_until_complete(asyncio.wait(ts))   # 相当于遍历列表中的元素
print(ret)  # 结果为二元组,第一个是set,里面有2个task对象for p in ret[0]:print(p.result())
import asyncio@asyncio.coroutine
def sleep():# count = 0# for i in range(3):#     yield count#     count += 1for i in range(3):yield from asyncio.sleep(1)  # 相当于沉睡1秒print('+++++++++++')return 'my return value = {}'.format(1000)print(asyncio.iscoroutinefunction(sleep))  # True
print(asyncio.iscoroutine(sleep()))  # True,注意sleep的括号不能丢,不然结果为Falsedef cb(fut):print('future = {} ~~~'.format(fut))loop = asyncio.get_event_loop()
print(type(loop))# Future =>Task  # Task是Future的子类
# future = asyncio.ensure_future(sleep())  # 确保得到一个future对象,对协程对象进行封装
#
# print(1, future)
# loop.run_until_complete(future)  # 一定会带你执行下ensure_future
# print(2, future)
#
# print(future.result())# task = asyncio.ensure_future(sleep())
# task = asyncio.create_task(sleep())  # python3.7版本以上才能使用
task = loop.create_task(sleep())task.add_done_callback(cb)print(3, task)
loop.run_until_complete(task)  # 只能放一个future对象,以后会有很多任务,部分任务执行完了,会调用回调函数
print(4, task)print(task.result(), '~~~~~~~')loop.close()

python3.4引入asyncio,使用装饰器,将生成器函数转换成协程函数,就可以在事件循环总执行了。ensure_future(coro_future),如果参数已经是future了,直接返回,如果是协程,则使用loop.create_task创建task,并返回task。

future对象都可以调用add_done_callback(fn)增加回调函数,回调函数是单参的,参数就是future对象。

注意:run_until_complete方法的返回结果,必须所有任务执行完才能看。

1.3 新语法

python3.5版本开始,python提供关键字async、await,在语言上原生支持协程。

import asyncioasync def a():  # async def 中不能出现yield,必须和await配合使用for i in range(3):print('a.x', i)# await wait()await asyncio.sleep(0.1)return 'a() return 1000'async def b():  # 不能再出现yieldfor i in 'abc':print('b.x', i)# await wait()  # await后往往是阻塞的函数,相当于yield from wait()await asyncio.sleep(0.1)return 'b() return 2000'loop = asyncio.get_event_loop()def cb(fut):print(fut.result())ts = []
for x in (a(), b()):t = asyncio.ensure_future(x)t.add_done_callback(cb)ts.append(t)task1 = loop.create_task(a())
task2 = loop.create_task(b())# 相当于遍历元组中的元素
ret = loop.run_until_complete(asyncio.wait(ts))
print(ret)  # 结果为二元组,第一个是set,里面有2个task对象for p in ret[0]:print(p.result())

async def用来定义协程函数,iscoroutinefunction()返回True。协程函数总可以不包含,协程函数中可以不包含await、async关键字,但不能使用yield关键字。如同生成器函数调用返回生成器对象一样,协程函数调用也会返回一个协程对象,iscoroutine返回True。await语句之后是awaitable对象,可以是协程或者是实现了__await__()方法的对象,await会暂停当前协程执行,使loop调度其他协程。

1.4 aiohttp

1.4.1 aiohttp Client

import asyncio
from aiohttp import ClientSessionasync def get_html(src: str):async with ClientSession() as session:  # 异步的with,会执行半截就暂停,执行其他的语句async with session.get(src) as res:print(res.status)return await res.text()async def main():url = await get_html('http://127.0.0.1:9988/12345?age=20&name=curry')print(url)loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()"""
import aiohttp
import asyncioasync def fetch(session, url):async with session.get(url) as response:return await response.text()async def main():async with aiohttp.ClientSession() as session:html = await fetch(session, 'http://python.org')print(html)loop = asyncio.get_event_loop()
loop.run_until_complete(main())
"""

1.4.2 aiohttp Server


# https://aiohttp.readthedocs.io/en/stable/, aiohttp是小型的网页设计库,比flask、Djiango要小巧
from aiohttp import webroutes = web.RouteTableDef()  # 改为装饰器
# https://aiohttp.readthedocs.io/en/stable/web_quickstart.html#run-a-simple-web-server"""
routes = web.RouteTableDef()@routes.get('/')
async def hello(request):return web.Response(text="Hello, world")app = web.Application()
app.add_routes(routes)
web.run_app(app)
"""@routes.get('/')
async def handle(request):# name = request.match_info.get('name', "Anonymous")# text = "Hello, " + nametext = "<html><body><h1>{}<h1></body></html>".format('你好,中国!')print(request)return web.Response(body=text, status=201, content_type='text/html', charset='utf-8')# 201是成功的把数据加入到了数据库,content_type默认是纯文本格式,现在设置为html@routes.get(r'/{id:\d+}')  # r的意思是把后面当做原始字符串,不转义,\d+是正则表达式
async def id_handle(request: web.Request):print(request.match_info.get('id', '0000'))  # 获取不到,用默认值0000text = 'path={}, qs={}'.format(request.path, request.query_string)  # qs为查询条件(查询字符串)return web.Response(body=text, status=200)  # 默认的状态码可以省略app = web.Application()# app.add_routes([web.get('/', handle),  # 路径映射
#                 # web.get('/{name}', handle),
#                 web.get('/{id}', id_handle)])  # {id}为字典,利用正则表达式匹配app.add_routes(routes)if __name__ == "__main__":web.run_app(app, host='127.0.0.1', port=9988)"""async def handle(request):name = request.match_info.get('name', "Anonymous")text = "Hello, " + namereturn web.Response(text=text)app = web.Application()
app.add_routes([web.get('/', handle),web.get('/{name}', handle)])web.run_app(app)
"""

 

 

这篇关于python中的协程(coroutine)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/652532

相关文章

python获取指定名字的程序的文件路径的两种方法

《python获取指定名字的程序的文件路径的两种方法》本文主要介绍了python获取指定名字的程序的文件路径的两种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 最近在做项目,需要用到给定一个程序名字就可以自动获取到这个程序在Windows系统下的绝对路径,以下

使用Python批量将.ncm格式的音频文件转换为.mp3格式的实战详解

《使用Python批量将.ncm格式的音频文件转换为.mp3格式的实战详解》本文详细介绍了如何使用Python通过ncmdump工具批量将.ncm音频转换为.mp3的步骤,包括安装、配置ffmpeg环... 目录1. 前言2. 安装 ncmdump3. 实现 .ncm 转 .mp34. 执行过程5. 执行结

Python实现批量CSV转Excel的高性能处理方案

《Python实现批量CSV转Excel的高性能处理方案》在日常办公中,我们经常需要将CSV格式的数据转换为Excel文件,本文将介绍一个基于Python的高性能解决方案,感兴趣的小伙伴可以跟随小编一... 目录一、场景需求二、技术方案三、核心代码四、批量处理方案五、性能优化六、使用示例完整代码七、小结一、

Python中 try / except / else / finally 异常处理方法详解

《Python中try/except/else/finally异常处理方法详解》:本文主要介绍Python中try/except/else/finally异常处理方法的相关资料,涵... 目录1. 基本结构2. 各部分的作用tryexceptelsefinally3. 执行流程总结4. 常见用法(1)多个e

Python中logging模块用法示例总结

《Python中logging模块用法示例总结》在Python中logging模块是一个强大的日志记录工具,它允许用户将程序运行期间产生的日志信息输出到控制台或者写入到文件中,:本文主要介绍Pyt... 目录前言一. 基本使用1. 五种日志等级2.  设置报告等级3. 自定义格式4. C语言风格的格式化方法

Python实现精确小数计算的完全指南

《Python实现精确小数计算的完全指南》在金融计算、科学实验和工程领域,浮点数精度问题一直是开发者面临的重大挑战,本文将深入解析Python精确小数计算技术体系,感兴趣的小伙伴可以了解一下... 目录引言:小数精度问题的核心挑战一、浮点数精度问题分析1.1 浮点数精度陷阱1.2 浮点数误差来源二、基础解决

使用Python实现Word文档的自动化对比方案

《使用Python实现Word文档的自动化对比方案》我们经常需要比较两个Word文档的版本差异,无论是合同修订、论文修改还是代码文档更新,人工比对不仅效率低下,还容易遗漏关键改动,下面通过一个实际案例... 目录引言一、使用python-docx库解析文档结构二、使用difflib进行差异比对三、高级对比方

深度解析Python中递归下降解析器的原理与实现

《深度解析Python中递归下降解析器的原理与实现》在编译器设计、配置文件处理和数据转换领域,递归下降解析器是最常用且最直观的解析技术,本文将详细介绍递归下降解析器的原理与实现,感兴趣的小伙伴可以跟随... 目录引言:解析器的核心价值一、递归下降解析器基础1.1 核心概念解析1.2 基本架构二、简单算术表达

从入门到精通详解Python虚拟环境完全指南

《从入门到精通详解Python虚拟环境完全指南》Python虚拟环境是一个独立的Python运行环境,它允许你为不同的项目创建隔离的Python环境,下面小编就来和大家详细介绍一下吧... 目录什么是python虚拟环境一、使用venv创建和管理虚拟环境1.1 创建虚拟环境1.2 激活虚拟环境1.3 验证虚

详解python pycharm与cmd中制表符不一样

《详解pythonpycharm与cmd中制表符不一样》本文主要介绍了pythonpycharm与cmd中制表符不一样,这个问题通常是因为PyCharm和命令行(CMD)使用的制表符(tab)的宽... 这个问题通常是因为PyCharm和命令行(CMD)使用的制表符(tab)的宽度不同导致的。在PyChar