python3 协程实战(python3经典编程案例)

简介: 该文章通过多个实战案例介绍了如何在Python3中使用协程来提高I/O密集型应用的性能,利用asyncio库以及async/await语法来编写高效的异步代码。

一. 定义协程

协程是轻量级线程,拥有自己的寄存机上下文和栈。
协程调度切换时,将寄存器上下文和栈保存到其他地方,再切回来时,恢复先前保存的寄存器上下文和栈。

协程的应用场景:I/O密集型任务,和多线程类似,但协程调用时在一个线程内进行的,是单线程,切换的开销小,因此,效率上略高于多线程。

python3.4加入了协程,以生成器对象为基础,python3.5加了async/await,使用协程更加方便。

python中使用协程最方便的库是asyncio,引入该库才能使用async和await关键字

  • async: 定义一个协程;async定义的方法无法直接执行,必须注册到时间循环中才能执行。
  • await: 用于临时挂起一个函数或方法的执行。

根据官方文档,await后面的对象必须是如下类型之一:

  • 一个原生的coroutine对象;
  • 一个由types.coroutine()修饰的生成器,这个生成器可以返回coroutine对象;
  • 一个包含await方法的对象返回的一个迭代器。

案例1:

import asyncio
import time


async def task():
    print(f"{time.strftime('%H:%M:%S')} task 开始 ")
    time.sleep(2)
    print(f"{time.strftime('%H:%M:%S')} task 结束")


coroutine = task()
print(f"{time.strftime('%H:%M:%S')} 产生协程对象 {coroutine},函数并未被调用")
loop = asyncio.get_event_loop()
print(f"{time.strftime('%H:%M:%S')} 开始调用协程任务")
start = time.time()
loop.run_until_complete(coroutine)
end = time.time()
print(f"{time.strftime('%H:%M:%S')} 结束调用协程任务, 耗时{end - start} 秒")

案例2:
为任务绑定回调函数

import asyncio
import time


async def _task():
    print(f"{time.strftime('%H:%M:%S')} task 开始 ")
    time.sleep(2)
    print(f"{time.strftime('%H:%M:%S')} task 结束")
    return "运行结束"


def callback(task):
    print(f"{time.strftime('%H:%M:%S')} 回调函数开始运行")
    print(f"状态:{task.result()}")


coroutine = _task()
print(f"{time.strftime('%H:%M:%S')} 产生协程对象 {coroutine},函数并未被调用")
task = asyncio.ensure_future(coroutine)  # 返回task对象
task.add_done_callback(callback)  # 为task增加一个回调任务
loop = asyncio.get_event_loop()
print(f"{time.strftime('%H:%M:%S')} 开始调用协程任务")
start = time.time()
loop.run_until_complete(task)
end = time.time()
print(f"{time.strftime('%H:%M:%S')} 结束调用协程任务, 耗时{end - start} 秒")

二. 并发

如果需要执行多次协程任务并尽可能的提高效率,这时可以定义一个task列表,然后使用asyncio的wait()方法执行即可。

import asyncio
import time


async def task():
    print(f"{time.strftime('%H:%M:%S')} task 开始 ")
    # 异步调用asyncio.sleep(1):
    await asyncio.sleep(2)
    # time.sleep(2)
    print(f"{time.strftime('%H:%M:%S')} task 结束" )

# 获取EventLoop:
loop = asyncio.get_event_loop()
# 执行coroutine
tasks = [task() for _ in range(5)]
start = time.time()
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
end = time.time()
print(f"用时 {end-start} 秒")

三. 异步请求

先启动一个简单的web服务器

from flask import Flask
import time

app = Flask(__name__)


@app.route('/')
def index():
    time.sleep(3)
    return 'Hello World!'


if __name__ == '__main__':
    app.run(threaded=True)

案例1:请求串行走下来,没有实现挂起。

import asyncio
import requests
import time

start = time.time()


async def request():
    url = 'http://127.0.0.1:5000'
    print(f'{time.strftime("%H:%M:%S")} 请求 {url}')
    response = requests.get(url)
    print(f'{time.strftime("%H:%M:%S")} 得到响应 {response.text}')

tasks = [asyncio.ensure_future(request()) for _ in range(5)]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))

end = time.time()
print(f'耗时 {end - start} 秒')

使用await将耗时等待的操作挂起,让出控制权。
当协程执行时遇到await, 时间循环就会将本协程挂起,转而去执行别的协程,知道其他的协程挂起或者执行完毕。

案例2:异步IO请求实例
将请求页面的代码封装成一个coroutine对象,在requests中尝试使用await挂起当前执行的I/O.

import asyncio
import requests
import time


async def get(url):
    return requests.get(url)


async def request():
    url = "http://127.0.0.1:5000"
    print(f'{time.strftime("%H:%M:%S")} 请求 {url}')
    response = await get(url)
    print(f'{time.strftime("%H:%M:%S")} 得到响应 {response.text}')


start = time.time()
tasks = [asyncio.ensure_future(request()) for _ in range(5)]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
end = time.time()
print(f"耗时 {end - start} 秒")

上面的带动并未达到预期的并发效果。原因是requests不是异步请求,无论如何改封装都无济于事,因此需要找真正的IO请求,aiohttp是一个支持异步请求的库,可以用它和anyncio配合,实现异步请求操作。
案例3:使用aiohttp库

import asyncio
import aiohttp
import time

now = lambda: time.strftime("%H:%M:%S")


async def get(url):
    session = aiohttp.ClientSession()
    response = await session.get(url)
    result = await response.text()
    await session.close()
    return result


async def request():
    url = "http://127.0.0.1:5000"
    print(f"{now()} 请求 {url}")
    result = await get(url)
    print(f"{now()} 得到响应 {result}")


start = time.time()
tasks = [asyncio.ensure_future(request()) for _ in range(5)]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))

end = time.time()
print(f"耗时 { end - start } 秒")

运行结果符合预期要求,耗时由15秒变成了3秒,实现了并发访问。

将任务数5改成100,运行时间也在3秒多一点,多出来的时间就是I/O时延了。
可见,使用异步协程之后,几乎可以在相同时间内实现成百上千次的网络请求。

相关文章
|
2月前
|
人工智能 安全 Shell
Jupyter MCP服务器部署实战:AI模型与Python环境无缝集成教程
Jupyter MCP服务器基于模型上下文协议(MCP),实现大型语言模型与Jupyter环境的无缝集成。它通过标准化接口,让AI模型安全访问和操作Jupyter核心组件,如内核、文件系统和终端。本文深入解析其技术架构、功能特性及部署方法。MCP服务器解决了传统AI模型缺乏实时上下文感知的问题,支持代码执行、变量状态获取、文件管理等功能,提升编程效率。同时,严格的权限控制确保了安全性。作为智能化交互工具,Jupyter MCP为动态计算环境与AI模型之间搭建了高效桥梁。
178 2
Jupyter MCP服务器部署实战:AI模型与Python环境无缝集成教程
|
2月前
|
存储 机器学习/深度学习 人工智能
多模态RAG实战指南:完整Python代码实现AI同时理解图片、表格和文本
本文探讨了多模态RAG系统的最优实现方案,通过模态特定处理与后期融合技术,在性能、准确性和复杂度间达成平衡。系统包含文档分割、内容提取、HTML转换、语义分块及向量化存储五大模块,有效保留结构和关系信息。相比传统方法,该方案显著提升了复杂查询的检索精度(+23%),并支持灵活升级。文章还介绍了查询处理机制与优势对比,为构建高效多模态RAG系统提供了实践指导。
429 0
多模态RAG实战指南:完整Python代码实现AI同时理解图片、表格和文本
|
2月前
|
机器学习/深度学习 人工智能 算法
Python+YOLO v8 实战:手把手教你打造专属 AI 视觉目标检测模型
本文介绍了如何使用 Python 和 YOLO v8 开发专属的 AI 视觉目标检测模型。首先讲解了 YOLO 的基本概念及其高效精准的特点,接着详细说明了环境搭建步骤,包括安装 Python、PyCharm 和 Ultralytics 库。随后引导读者加载预训练模型进行图片验证,并准备数据集以训练自定义模型。最后,展示了如何验证训练好的模型并提供示例代码。通过本文,你将学会从零开始打造自己的目标检测系统,满足实际场景需求。
492 0
Python+YOLO v8 实战:手把手教你打造专属 AI 视觉目标检测模型
|
2月前
|
数据采集 存储 数据可视化
2025python实战:利用海外代理IP验证广告投放效果
本文介绍了如何利用Python结合海外代理IP技术,验证广告在不同国家的实际投放效果。通过模拟各地网络环境访问广告页面,检查内容是否与计划一致,并生成曝光报告。具体实现包括:获取高质量代理IP、使用Selenium或Playwright模拟用户行为、解析广告内容及生成可视化报告。案例显示,该方法能有效确保广告精准投放,优化策略并节省预算。
|
10月前
|
调度 Python
揭秘Python并发编程核心:深入理解协程与异步函数的工作原理
在Python异步编程领域,协程与异步函数成为处理并发任务的关键工具。协程(微线程)比操作系统线程更轻量级,通过`async def`定义并在遇到`await`表达式时暂停执行。异步函数利用`await`实现任务间的切换。事件循环作为异步编程的核心,负责调度任务;`asyncio`库提供了事件循环的管理。Future对象则优雅地处理异步结果。掌握这些概念,可使代码更高效、简洁且易于维护。
124 1
|
9月前
|
数据采集 调度 Python
Python编程异步爬虫——协程的基本原理(一)
Python编程异步爬虫——协程的基本原理(一)
83 0
|
9月前
|
数据采集 Python
Python编程异步爬虫——协程的基本原理(二)
Python编程异步爬虫——协程的基本原理(二)
67 0
|
12月前
|
调度 Python
揭秘Python并发编程核心:深入理解协程与异步函数的工作原理
【7月更文挑战第15天】Python异步编程借助协程和async/await提升并发性能,减少资源消耗。协程(async def)轻量级、用户态,便于控制。事件循环,如`asyncio.get_event_loop()`,调度任务执行。异步函数内的await关键词用于协程间切换。回调和Future对象简化异步结果处理。理解这些概念能写出高效、易维护的异步代码。
133 2
|
前端开发 API 索引
Python3.5 协程原理
本文讲的是Python3.5 协程原理,作为 Python 核心开发者之一,让我很想了解这门语言是如何运作的。我发现总有一些阴暗的角落我对其中错综复杂的细节不是很清楚,但是为了能够有助于 Python 的一些问题和其整体设计,我觉得我应该试着去理解 Python 的核心语法和内部运作机制。
1745 0
|
4月前
|
机器学习/深度学习 存储 设计模式
Python 高级编程与实战:深入理解性能优化与调试技巧
本文深入探讨了Python的性能优化与调试技巧,涵盖profiling、caching、Cython等优化工具,以及pdb、logging、assert等调试方法。通过实战项目,如优化斐波那契数列计算和调试Web应用,帮助读者掌握这些技术,提升编程效率。附有进一步学习资源,助力读者深入学习。

推荐镜像

更多