异步编程和asyncio

news2024/12/28 20:12:00

        介绍异步编程的重要性和在Python中的应用,特别是在I/O密集型任务和网络编程场景下。

目录

理解异步编程

异步编程基本概念

任务与Future

异步编程的工作原理

事件循环

协程(Coroutines)

异步与同步代码的结合

深入asyncio模块

事件循环(Event Loop)

协程(Coroutines)

使用async和await

任务(Tasks)

异步I/O和网络操作

异步编程实战

1. 异步HTTP请求

2. 异步文件操作

3. 异步数据库操作

4. 异步Web服务器


理解异步编程

        异步编程是一种编程范式,它允许程序在等待某些操作完成时继续执行其他任务,而不是阻塞等待。这在处理I/O密集型任务(如网络请求、文件读写等)时尤其有用,因为这些操作的延迟往往不可预测且很难避免。

异步编程基本概念

异步编程允许程序在等待操作完成时继续执行其他任务,这在处理I/O密集型操作时尤其有用。

# 异步函数示例
import asyncio

async def hello_world():
    print("Hello, world!")

# 运行事件循环,直到hello_world()协程执行完成
asyncio.run(hello_world())

在这个例子中,hello_world是一个异步函数,使用async def定义。asyncio.run(hello_world())运行事件循环,执行hello_world协程。

任务与Future

任务是对协程的进一步抽象,它们在事件循环中被调度。asyncio.gather可以并发运行多个任务。

async def count():
    print("One")
    await asyncio.sleep(1)
    print("Two")

async def main():
    # 创建并同时运行两个count()协程
    await asyncio.gather(count(), count())

asyncio.run(main())

异步编程的工作原理

        在同步编程中,如果一个函数需要等待某个操作完成(比如,等待网络响应),它会阻塞程序的执行,直到操作完成。而在异步编程中,当遇到这种等待情况时,程序可以“挂起”当前任务,并开始执行另一个任务,直到原任务的等待操作完成,然后再回来继续执行。

        这种方式依赖于事件循环(Event Loop),它是异步编程的核心。事件循环不断检查是否有任务完成了等待的操作,如果有,则将这些任务重新加入到任务队列中继续执行。

事件循环

        事件循环是异步编程中管理和调度任务执行的机制。在Python的asyncio模块中,事件循环的概念是通过事件循环对象来实现的。

import asyncio

# 获取当前事件循环
loop = asyncio.get_event_loop()

# 事件循环:运行直到某个任务完成
loop.run_until_complete(async_function())

# 关闭事件循环
loop.close()

        在这个例子中,async_function()代表了一个异步函数,它可能包含了诸如网络请求等需要等待的操作。run_until_complete()方法会运行事件循环,直到传入的协程执行完成。

协程(Coroutines)

        协程是Python中实现异步编程的关键。在Python中,协程是一种特殊类型的函数,它的定义使用async def语法。协程内部可以使用await关键字挂起协程的执行,等待异步操作完成。

async def async_function():
    # 模拟异步操作,比如网络请求
    await asyncio.sleep(1)
    print("异步操作完成")

# 运行协程
asyncio.run(async_function())

        在async_function中,await asyncio.sleep(1)模拟了一个异步操作。await关键字使得协程的执行在这里暂停,让出控制权给事件循环,直到asyncio.sleep(1)完成,协程才会继续执行。

异步与同步代码的结合

        在实际应用中,异步代码经常需要与同步代码相结合。asyncio提供了多种机制来支持这种结合,如run_in_executor方法,它可以用于在事件循环中执行同步代码。

def sync_function():
    # 模拟耗时的同步操作
    time.sleep(1)
    print("同步操作完成")

async def main():
    loop = asyncio.get_running_loop()
    # 在事件循环中运行同步函数
    await loop.run_in_executor(None, sync_function)

# 运行主协程
asyncio.run(main())

        这个例子展示了如何在异步程序中运行同步代码。run_in_executor方法允许将同步函数sync_function在事件循环中作为异步任务执行,从而避免阻塞事件循环。

        通过这种方式,异步编程模型允许你构建出响应更快、性能更高的应用,特别是在处理大量I/O操作时。在下一章中,我们将深入探讨asyncio模块,了解其提供的工具和机制,以及如何使用它们来构建高效的异步应用。

深入asyncio模块

        asyncio是Python标准库的一部分,提供了编写单线程并发代码的基础设施,特别适用于I/O密集型任务。它使用async/await语法,是实现异步编程的主要方法之一。

事件循环(Event Loop)

        事件循环是asyncio中的核心概念,负责管理和分发事件。所有的异步操作都是在事件循环中执行的。

import asyncio

async def main():
    print('Hello')
    await asyncio.sleep(1)
    print('World')

# asyncio.run() 是 Python 3.7+ 中引入的简化事件循环管理的函数
asyncio.run(main())

        在这个例子中,asyncio.run(main())启动了事件循环,运行main()协程。await asyncio.sleep(1)会暂停main()协程的执行,让出控制权给事件循环,直到延时完成。

协程(Coroutines)

        协程是通过async def定义的异步函数。在协程内部,可以使用await来挂起协程的执行,等待另一个协程完成。

async def fetch_data():
    print("Start fetching")
    await asyncio.sleep(2)  # 模拟I/O操作
    print("Data fetched")
    return {'data': 1}

async def print_numbers():
    for i in range(10):
        print(i)
        await asyncio.sleep(0.25)

async def main():
    task1 = asyncio.create_task(fetch_data())
    task2 = asyncio.create_task(print_numbers())

    # 等待两个协程任务完成
    await task1
    await task2

asyncio.run(main())

fetch_dataprint_numbers是通过async def定义的协程。asyncio.create_task()用于并发运行这两个协程。这里,fetch_data模拟了异步的I/O操作,而print_numbers则在这个操作进行时并发运行。

使用asyncawait

  asyncawait是异步编程的核心,async将函数声明为协程函数,await用于挂起协程的执行,等待异步操作完成。

async def compute(x, y):
    print("Compute %s + %s ..." % (x, y))
    await asyncio.sleep(1.0)
    return x + y

async def main():
    result = await compute(1, 2)
    print("Result:", result)

asyncio.run(main())

        这个例子中,compute协程在执行过程中使用await asyncio.sleep(1.0)挂起,模拟了一个耗时的计算操作。main协程等待compute的结果,然后打印。

任务(Tasks)

任务用于并发调度协程,是对协程的一种封装。

async def task_func():
    print('Task start')
    await asyncio.sleep(1)  # 模拟I/O操作
    print('Task finished')

async def main():
    task = asyncio.create_task(task_func())
    await task  # 等待任务完成

asyncio.run(main())

在这个例子中,asyncio.create_task()创建了一个任务,这个任务包装了task_func协程。await task会等待任务完成,这期间事件循环可以运行其他任务或协程。

异步I/O和网络操作

asyncio提供了一套用于执行异步网络操作的高级API,如asyncio.open_connection用于TCP连接。

async def tcp_echo_client(message):
    reader, writer = await asyncio.open_connection('127.0.0.1', 8888)

    print(f'Send: {message}')
    writer.write(message.encode())
    await writer.drain()

    data = await reader.read(100)
    print(f'Received: {data.decode()}')

    writer.close()
    await writer.wait_closed()

asyncio.run(tcp_echo_client('Hello World!'))

异步编程实战

在本章中,我们将探索如何将asyncio应用于实际场景中,通过具体的示例展示异步编程的强大功能和高效性。

1. 异步HTTP请求

在进行网络请求时,异步编程能显著提高性能。以下示例展示了如何使用aiohttp库执行异步HTTP请求:

import aiohttp
import asyncio

async def fetch_url(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_url(session, 'https://www.example.com')
        print(html[:100])  # 打印获取到的HTML内容的前100个字符

asyncio.run(main())

2. 异步文件操作

异步文件操作可以提高I/O密集型应用的性能。以下示例展示了如何使用aiofiles库进行异步文件读写操作:

import aiofiles
import asyncio

async def write_to_file(filename, content):
    async with aiofiles.open(filename, 'w') as f:
        await f.write(content)

async def read_from_file(filename):
    async with aiofiles.open(filename, 'r') as f:
        content = await f.read()
    return content

async def main():
    await write_to_file('example.txt', 'Hello, asyncio!')
    content = await read_from_file('example.txt')
    print(content)

asyncio.run(main())

3. 异步数据库操作

数据库操作是另一个适合应用异步编程的场景。以下示例使用aiomysql库进行异步数据库操作:

import aiomysql
import asyncio

async def fetch_data(loop):
    conn = await aiomysql.connect(host='127.0.0.1', port=3306,
                                  user='root', password='password',
                                  db='test_db', loop=loop)
    async with conn.cursor() as cur:
        await cur.execute("SELECT 42;")
        (result,) = await cur.fetchone()
        print("Result:", result)
    conn.close()

loop = asyncio.get_event_loop()
loop.run_until_complete(fetch_data(loop))

4. 异步Web服务器

使用aiohttp库,你还可以构建一个简单的异步Web服务器:

from aiohttp import web
import asyncio

async def handle(request):
    return web.Response(text="Hello, asyncio!")

app = web.Application()
app.add_routes([web.get('/', handle)])

web.run_app(app)

        通过本文的深入解读,我们已经对Python中的异步编程有了全面的了解。从基础的async和await,到asyncio模块的高级应用,我们学习了如何利用这些强大的工具来提升程序的性能和响应速度。实际应用案例展示了异步编程在处理网络请求、文件I/O和数据库操作中的高效性。随着技术的不断进步,异步编程将在未来的软件开发中扮演越来越重要的角色。希望本文能够为你在这个领域的探索提供有价值的指南和灵感。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1509602.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

day61 数据库约束 jdbc

回顾 1 SQL语句的分类 2创建表的语法 create table 表名( 列名 数据类型 not null, 列名 数据类型 ); 3 删除表 drop table 表名; 数据完整性分类 1实体完整性 (表中每条记录唯一) 2域完整性 3引用完整性 数据完整性约束 实体完整性约束 主键约束 表…

使用 mysqldump 迁移 MySQL 表 OceanBase

使用 mysqldump 迁移 MySQL 表 OceanBase 一、什么是mysqldump二、使用mysqldump导出MySQL数据三、将数据导入到OceanBase四、注意 一、什么是mysqldump mysqldump 是 MySQL 数据库管理系统中的一个工具,用于将数据库中的数据导出为文本文件。它可以将整个数据库、…

spring boot 访问 static public 目录下的静态资源报404解决办法

1.前提是你没有修改spring boot 默认拦截路径,跟默认访问资源的目录。 在idea 设置中 把 compiler 下的 Buid project automatically 勾选上

多场成像,快速提高机器视觉检测能力--51camera

多阵列CMOS传感器与芯片级涂层二向色滤光片相结合,可在单次扫描中同时捕获明场、暗场和背光图像。 多场成像是一种新的成像技术,它可以在不同的光照条件下同时捕获多幅图像。再加上时间延迟积分(TDI),这种新兴的成像技术可以克服许多限制的传…

关于VScode中使用yapf,更改settings.json文件中的column_limit没有作用的解决方法。

目录 一、yapf一行中最大字符限制修改 二、忽略flake8对一行中最大字符限制警告 写在前面,不知道啥情况,按照常见的方式更改settings.json文件不起作用,如这些大佬的文章VSCode配置yapf python格式化 配置一行的长度 、vscode中使用yapf自动格…

思科网络中如何配置扩展ACL协议

一、什么是扩展ACL协议?有什么作用及配置方法? (1)扩展ACL(Extended Access Control List)协议是一种网络安全协议,用于在路由器或防火墙上实现对数据包的细粒度访问控制。与标准ACL相比&#…

【Python】牛客网—软件开发-Python专项练习

专栏文章索引:Python 1.(单选)下面哪个是Python中不可变的数据结构? A.set B.list C.tuple D.dict 可变数据类型:列表list[ ]、字典dict{ }、集合set{ }(能查询,也可更改)数据发生改…

对象注入的几种方式

⭐ 作者:小胡_不糊涂 🌱 作者主页:小胡_不糊涂的个人主页 📀 收录专栏:JavaEE 💖 持续更文,关注博主少走弯路,谢谢大家支持 💖 注入对象 1. 属性注入2. 构造方法注入3. S…

RabbitMQ详解与常见问题解决方案

文章目录 什么是 RabbitMQ?RabbitMQ 和 AMQP 是什么关系?RabbitMQ 的核心组件有哪些?RabbitMQ 中有哪几种交换机类型?Direct Exchange(直连交换机)Topic Exchange(主题交换机)Headers Exchange(头部交换机)Fanout Exchange(广播交…

(黑马出品_07)SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式

(黑马出品_07)SpringCloudRabbitMQDockerRedis搜索分布式 微服务技术分布式搜索 今日目标1.数据聚合1.1.聚合的种类1.2.DSL实现聚合1.2.1.Bucket聚合语法1.2.2.聚合结果排序1.2.3.限定聚合范围1.2.4.Metric聚合语法1.2.5.小…

01_04_JavaWEB03_XML、Tomcat、http

XML_Tomcat10_HTTP 参考尚硅谷再总结复习 一 XML XML是EXtensible Markup Language的缩写,翻译过来就是可扩展标记语言。所以很明显,XML和HTML一样都是标记语言,也就是说它们的基本语法都是标签。 可扩展 三个字表面上的意思是XML允许自定义…

云服务器2核4G配置,阿里云和腾讯云哪个便宜?性能更好?

租用2核4G服务器费用多少?2核4G云服务器多少钱一年?1个月费用多少?阿里云2核4G服务器30元3个月、轻量应用服务器2核4G4M带宽165元一年、企业用户2核4G5M带宽199元一年;腾讯云轻量2核4G服务器5M带宽165元一年、252元15个月、540元三…

RNN实战

本主要是利用RNN做多分类任务,在熟悉RNN训练的过程中,我们可以理解 1)超参数 batch_size和pad_size对训练过程的影响。 2)文本处理过程中是如何将文本的文字表示转化为向量表示 3)RNN梯度消失和序列长度的关系 4&#…

企商在线CTO楼炜:论云计算与产业互联网

024年全国两会召开之际,3月4日,全国政协委员、京东集团技术委员会主席曹鹏提交了《发挥产业互联网平台作用 打造实体产业数字化转型直效通道》提案,提出了产业互联网平台在整合供应链、资金、技术、资讯、培训、人才等各类资源的重要作用。云…

python实现生成树

生成树 生成树(Spanning Tree)是一个连通图的生成树是图的极小连通子图,它包含图中的所有顶点,并且只含尽可能少的边。这意味着对于生成树来说,若砍去它的一条边,则会使生成树变成非连通图;若给…

ChatGpt只能看,但无法发送消息的解决办法

这几天发现chatgpt没法发送消息了,我以为是网络问题,又过了几天还是不能发,我以为是梯子的问题,可给我急坏了,于是我用无痕模式发现可以访问额. 但是无痕模式毕竟不是长久之计,于是找到了一个方法 1.首先把电脑缓存全清除了 第一种方法: 快捷键是 : ctrlshiftdel (这会吧浏览…

电脑切屏卡顿,尤其是打游戏时切屏卡顿问题解决方法

博主在打游戏时喜欢切后台但是最近发现切屏尤其慢,异常卡顿,但是是新换的电脑,所以苦恼了半天,上网搜也没有结果,说的都是些配置低,系统文件损坏等问题,所以再检查分辨率时发现问题所在 屏幕分辨…

Visual Studio 2022 配置“Debug|x64”的 Designtime 生成失败。IntelliSense 可能不可用。

今天写代码,无缘无故就给我整个这个错误出来,我一头雾水。 经过我几个小时的奋战,终于解决问题 原因就是这个Q_INTERFACES()宏,我本想使用Q_DECLARE_INTERFACE Q_INTERFACES这两个Qt宏实现不继承QObject也能使用qobjec…

jmeter压测实战

1,设置HTTP请求默认值 2,设置全局变量 3,新建线程组 4,设置私钥 5,每个接口新建一个事务控制器 6,新建Java请求 对于有sign签名的需要将jar包放在apache-jmeter-5.4.1\apache-jmeter-5.4.1\lib\ext目录下,然后引入进来。 除此之外,还需要下载bouncycastle.jar包放在…

地表径流量分布数据/水文站点分布数据

天然河川径流资料对于认识水文自然规律、国家水资源可持续利用以及适应气候变化政策制定具有重要意义。我国现有的天然河川径流资料存在时间缺失率高、水文站点密度不足等问题,在年际和季节变化尺度上存在较大的流量偏差。 引言 大气降水落到地面后,一部…