1. 异步编程概述

异步编程是一种编程范式,用于处理那些需要等待I/O操作完成或者耗时任务的情况。在传统的同步编程中,代码会按照顺序逐行执行,直到遇到一个耗时操作,它会阻塞程序的执行直到操作完成。这种阻塞式的模型在某些场景下效率低下,因为代码在等待操作完成时无法执行其他任务。

异步编程通过使用非阻塞I/O和协程(coroutine)来提高效率。协程是一种特殊的函数,可以在执行过程中暂停和恢复。当一个协程遇到一个耗时操作时,它会暂停自己的执行,让出控制权给其他协程,从而实现并发执行。async/await关键字是Python中处理协程的语法工具

2. async/await关键字

async关键字

async是一个关键字,用于定义一个协程函数。协程函数可以通过使用await关键字来暂停自身的执行,等待其他协程或异步操作完成。

以下是一个简单的示例,展示了如何定义一个协程函数:

import asyncio

async def my_coroutine():
print("Coroutine started")
await asyncio.sleep(1)
print("Coroutine resumed")
return "Result"

my_coroutine是一个协程函数。它使用了async关键字进行定义,并包含了一个await语句来暂停执行。

await关键字

await是另一个关键字,用于暂停协程函数的执行,等待另一个协程、异步操作或者Future对象完成。

以下是一个使用await的示例:

import asyncio

async def my_coroutine():
print("Coroutine started")
await asyncio.sleep(1)
print("Coroutine resumed")
return "Result" async def main():
result = await my_coroutine()
print(f"Result: {result}") asyncio.run(main())

在上面的示例中,main函数是一个协程函数,它使用await关键字来等待my_coroutine协程函数的执行结果。当await语句执行时,main函数会暂停自身的执行,直到my_coroutine协程函数完成并返回结果。

需要注意的是,await关键字只能在协程函数中使用。如果你在普通的同步函数中使用await,会导致语法错误。

3. 异步事件循环

异步编程的核心是事件循环(event loop)。事件循环负责调度和执行协程,确保它们按照正确的顺序执行。

在Python中,可以使用asyncio模块提供的事件循环来创建和管理协程。

以下是一个使用事件循环的示例:

import asyncio

async def my_coroutine():
print("Coroutine started")
await asyncio.sleep(1)
print("Coroutine resumed")
return "Result" async def main():
result = await my_coroutine()
print(f"Result: {result}") loop = asyncio.get_event_loop()
loop.run_until_complete(main())

在上面的示例中,asyncio.get_event_loop()用于获取默认的事件循环对象。然后,通过调用run_until_complete方法来运行main协程函数,直到它完成

异步编程最常见的用例是处理I/O操作,例如读写文件或与网络通信。在传统的同步编程中,这些操作会阻塞程序的执行,直到操作完成。而在异步编程中,可以使用异步IO操作来实现非阻塞的并发执行。

4. 异步IO操作

Python提供了asyncio模块来处理异步IO操作。asyncio中的一些常用函数和类包括:

  • asyncio.sleep(delay): 创建一个休眠指定时间的协程。
  • asyncio.open_connection(host, port): 创建一个协程,用于与指定的主机和端口建立网络连接。
  • asyncio.open_unix_connection(path): 创建一个协程,用于与指定路径的UNIX域套接字建立连接。
  • asyncio.start_server(client_connected_cb, host, port): 创建一个协程,用于监听指定主机和端口的连接请求,并在每次连接时调用client_connected_cb回调函数。

以下是一个使用异步IO操作的示例:

import asyncio

async def read_data():
# 模拟异步IO读取操作
await asyncio.sleep(1)
return "Data" async def write_data(data):
# 模拟异步IO写入操作
await asyncio.sleep(1)
print(f"Data written: {data}") async def main():
data = await read_data()
await write_data(data) loop = asyncio.get_event_loop()
loop.run_until_complete(main())

在上面的示例中,read_datawrite_data函数模拟了异步的IO读取和写入操作。在main函数中,我们使用await关键字等待读取操作完成,然后将结果传递给写入操作。

执行步骤如下:

  1. 首先,创建一个事件循环(Event Loop)对象,使用asyncio.get_event_loop()获取默认的事件循环。

  2. 定义了三个协程函数:read_data()write_data()main()

  3. 调用loop.run_until_complete(main()),将main()协程任务提交给事件循环并运行,直到main()协程完成。

  4. main()协程中,首先调用read_data()协程函数。这会启动read_data()协程,并在await asyncio.sleep(1)处暂停执行,等待1秒钟。

  5. 在暂停执行的同时,事件循环可以切换到其他可运行的协程,例如write_data()协程。

  6. write_data()协程同样会启动,并在await asyncio.sleep(1)处暂停执行,等待1秒钟。

  7. write_data()协程暂停执行时,事件循环没有其他可运行的协程,因此它会等待,直到有其他协程可运行。

  8. 在等待1秒钟后,read_data()协程恢复执行。它完成后,返回结果"Data"。

  9. main()协程接收到read_data()协程的返回结果,将其赋值给data变量。

  10. main()协程继续执行,调用write_data(data)协程。

  11. write_data()协程恢复执行,打印出"data"的值。

  12. main()协程完成,事件循环结束。

在这个过程中,通过使用await关键字,协程能够在等待IO操作完成时暂停执行,并允许事件循环切换到其他协程。这种方式下,IO操作可以以异步的方式执行,而不会阻塞整个程序的执行流程。

5. 并发执行多个协程

异步编程的一个关键优势是能够并发执行多个协程,以提高程序的性能。

asyncio提供了多种方式来实现协程的并发执行,其中最常用的方式是使用asyncio.gather函数。

以下是一个并发执行多个协程的示例:

import asyncio

async def coroutine1():
await asyncio.sleep(1)
print("Coroutine 1 completed") async def coroutine2():
await asyncio.sleep(2)
print("Coroutine 2 completed") async def coroutine3():
await asyncio.sleep(0.5)
print("Coroutine 3 completed") async def main():
await asyncio.gather(coroutine1(), coroutine2(), coroutine3()) loop = asyncio.get_event_loop()
loop.run_until_complete(main())

在上面的示例中,coroutine1coroutine2coroutine3是三个协程函数。在main函数中,我们使用asyncio.gather函数来并发执行这三个协程。asyncio.gather接受一个可变数量的协程参数,并返回一个新的协程,该协程在所有给定的协程完成后完成。执行循序为当执行到 coroutine1中的await时,此协程会挂起,执行权交给新的协程 coroutine2开始执行,以此类推。当 coroutine3 等待0.5s执行完毕后,执行权重新回到coroutine3 ,继续执行一下语句,其他同理。

需要注意的是,Python的协程是单线程的,通过事件循环来实现并发执行。当一个协程遇到阻塞的IO操作时,它会暂停自身的执行,并切换到下一个可执行的协程。这种切换是由事件循环调度

浅谈Python异步编程的更多相关文章

  1. 浅谈.Net异步编程的前世今生----APM篇

    前言 在.Net程序开发过程中,我们经常会遇到如下场景: 编写WinForm程序客户端,需要查询数据库获取数据,于是我们根据需求写好了代码后,点击查询,发现界面卡死,无法响应.经过调试,发现查询数据库 ...

  2. 浅谈.Net异步编程的前世今生----EAP篇

    前言 在上一篇博文中,我们提到了APM模型实现异步编程的模式,通过使用APM模型,可以简化.Net中编写异步程序的方式,但APM模型本身依然存在一些缺点,如无法得知操作进度,不能取消异步操作等. 针对 ...

  3. 新手浅谈Task异步编程和Thread多线程编程

    初学Task的时候上网搜索,看到很多文章的标题都是task取代thread等等相关,我也一直以为task和thread是一类,其实task是.net4.0提出的异步编程,在之前.net1.0有dele ...

  4. 浅谈python面向对象编程和面向过程编程的区别

    面向过程:分析出解决问题所需要的步骤,然后用函数把这些步骤一步步实现,使用的时候再一个个的依次调用即可. 优点:性能高 缺点:相较于面向对象而言,不易维护,不易复用,不易扩展 适合于小型的项目面向对象 ...

  5. 浅谈JavaScript异步编程

    单线程模式 我们知道JS的执行环境是单线程的,是因为JS语言最早是运行在浏览器端的语言,目的是为了实现页面上的动态交互.实现动态交互的核心就是DOM操作,因此决定了JS必须是单线程模式工作.我们来假设 ...

  6. 开发技术--浅谈python基础知识

    开发|浅谈python基础知识 最近复习一些基础内容,故将Python的基础进行了总结.注意:这篇文章只列出来我觉得重点,并且需要记忆的知识. 前言 目前所有的文章思想格式都是:知识+情感. 知识:对 ...

  7. [转帖]浅谈响应式编程(Reactive Programming)

    浅谈响应式编程(Reactive Programming) https://www.jianshu.com/p/1765f658200a 例子写的非常好呢. 0.9312018.02.14 21:22 ...

  8. 浅谈Python时间模块

    浅谈Python时间模块 今天简单总结了一下Python处理时间和日期方面的模块,主要就是datetime.time.calendar三个模块的使用.希望这篇文章对于学习Python的朋友们有所帮助 ...

  9. 浅谈Python在信息学竞赛中的运用及Python的基本用法

    浅谈Python在信息学竞赛中的运用及Python的基本用法 前言 众所周知,Python是一种非常实用的语言.但是由于其运算时的低效和解释型编译,在信息学竞赛中并不用于完成算法程序.但正如LRJ在& ...

  10. 深入理解 Python 异步编程(上)

    http://python.jobbole.com/88291/ 前言 很多朋友对异步编程都处于"听说很强大"的认知状态.鲜有在生产项目中使用它.而使用它的同学,则大多数都停留在知 ...

随机推荐

  1. Navicat 连接Oracle ORA-28547: connection to server failed, probable Oracle Net admin error

    Navicat 连接 Oracle 报 ORA-03135: connection lost contact ORA-28547: connection to server failed, proba ...

  2. 一文了解io.ReadAtLeast函数

    1. 引言 io.ReadAtLeast 函数是Go标准库提供的一个非常好用的函数,能够指定从数据源最少读取到的字节数.本文我们将从io.ReadAtLeast 函数的基本定义出发,讲述其基本使用和实 ...

  3. 图像处理评价指标_划分系数Vpc划分熵Vpe

    划分系数划分熵 评价指标划分系数Vpc和划分熵Vpe能够反映分割矩阵的模糊程度,Vpc数值越大,分割矩阵的模糊性越小,分割效果越好:Vpe数值越小,像素分类越准确,分割效果越好. (1)划分系数Vpc ...

  4. 解读 --- yield 关键字

    引言 yield关键字是 C# 中的一种语言特性,用于在枚举器中简化迭代器的实现.它使得开发人员可以通过定义自己的迭代器来简化代码,而不必手动实现 IEnumerable 和 IEnumerator ...

  5. Oracle备份与还原(实用版)

    Oracle备份与还原 EXP和IMP是客户端工具程序,它们既可以在客户端使用,也可以在服务端使用. EXPDP和IMPDP是服务端的工具程序,他们只能在ORACLE服务端使用,不能在客户端使用. I ...

  6. DNS与CDN技术

    参考链接: CDN原理简单介绍 浅析:DNS解析和CDN加速 DNS报文格式解析

  7. Vue3 路由优化,使页面初次渲染效率翻倍

    3996 条路由? addRoute函数用了大约1s才执行完毕.通过观察,发现居然有3996条路由记录. 可是项目并没有这么多的页面啊~ 重复路由 let routes: Array<Route ...

  8. 为什么NoSQL不支持事务

    为什么NoSQL不支持事务 1. 背景 看书<Neo4j权威指南>的时候,发现个问题:日常的NoSQL都不支持事务(ACID). 2. 问题 事务对数据的存储过程是有利的,既然事情是有利的 ...

  9. 网络请求-Android篇(Okhttp和Retrofit)

    一.OkHttp的介绍和基本用法 OkHttp是一个流行的开源Java和Android应用程序的HTTP客户端.它由Square Inc.开发,提供了一种简单高效的方式来进行应用程序中的HTTP请求. ...

  10. CodeForces 1367F1 Flying Sort (Easy Version)

    题意 给一个长度为\(n\)的数组,数组中的数互不相同,你可以有两种操作 将某一个数放置在数组开头 将某一个数放置在数组结尾 问最小操作多少次可以得到一个递增数列 分析 因为数组中的数很大,我们可以将 ...