• 异步编程和asyncio


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

    目录

    理解异步编程

    异步编程基本概念

    任务与Future

    异步编程的工作原理

    事件循环

    协程(Coroutines)

    异步与同步代码的结合

    深入asyncio模块

    事件循环(Event Loop)

    协程(Coroutines)

    使用async和await

    任务(Tasks)

    异步I/O和网络操作

    异步编程实战

    1. 异步HTTP请求

    2. 异步文件操作

    3. 异步数据库操作

    4. 异步Web服务器


    理解异步编程

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

    异步编程基本概念

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

    1. # 异步函数示例
    2. import asyncio
    3. async def hello_world():
    4. print("Hello, world!")
    5. # 运行事件循环,直到hello_world()协程执行完成
    6. asyncio.run(hello_world())

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

    任务与Future

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

    1. async def count():
    2. print("One")
    3. await asyncio.sleep(1)
    4. print("Two")
    5. async def main():
    6. # 创建并同时运行两个count()协程
    7. await asyncio.gather(count(), count())
    8. asyncio.run(main())

    异步编程的工作原理

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

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

    事件循环

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

    1. import asyncio
    2. # 获取当前事件循环
    3. loop = asyncio.get_event_loop()
    4. # 事件循环:运行直到某个任务完成
    5. loop.run_until_complete(async_function())
    6. # 关闭事件循环
    7. loop.close()

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

    协程(Coroutines)

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

    1. async def async_function():
    2. # 模拟异步操作,比如网络请求
    3. await asyncio.sleep(1)
    4. print("异步操作完成")
    5. # 运行协程
    6. asyncio.run(async_function())

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

    异步与同步代码的结合

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

    1. def sync_function():
    2. # 模拟耗时的同步操作
    3. time.sleep(1)
    4. print("同步操作完成")
    5. async def main():
    6. loop = asyncio.get_running_loop()
    7. # 在事件循环中运行同步函数
    8. await loop.run_in_executor(None, sync_function)
    9. # 运行主协程
    10. asyncio.run(main())

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

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

    深入asyncio模块

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

    事件循环(Event Loop)

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

    1. import asyncio
    2. async def main():
    3. print('Hello')
    4. await asyncio.sleep(1)
    5. print('World')
    6. # asyncio.run() 是 Python 3.7+ 中引入的简化事件循环管理的函数
    7. asyncio.run(main())

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

    协程(Coroutines)

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

    1. async def fetch_data():
    2. print("Start fetching")
    3. await asyncio.sleep(2) # 模拟I/O操作
    4. print("Data fetched")
    5. return {'data': 1}
    6. async def print_numbers():
    7. for i in range(10):
    8. print(i)
    9. await asyncio.sleep(0.25)
    10. async def main():
    11. task1 = asyncio.create_task(fetch_data())
    12. task2 = asyncio.create_task(print_numbers())
    13. # 等待两个协程任务完成
    14. await task1
    15. await task2
    16. asyncio.run(main())

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

    使用asyncawait

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

    1. async def compute(x, y):
    2. print("Compute %s + %s ..." % (x, y))
    3. await asyncio.sleep(1.0)
    4. return x + y
    5. async def main():
    6. result = await compute(1, 2)
    7. print("Result:", result)
    8. asyncio.run(main())

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

    任务(Tasks)

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

    1. async def task_func():
    2. print('Task start')
    3. await asyncio.sleep(1) # 模拟I/O操作
    4. print('Task finished')
    5. async def main():
    6. task = asyncio.create_task(task_func())
    7. await task # 等待任务完成
    8. asyncio.run(main())

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

    异步I/O和网络操作

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

    1. async def tcp_echo_client(message):
    2. reader, writer = await asyncio.open_connection('127.0.0.1', 8888)
    3. print(f'Send: {message}')
    4. writer.write(message.encode())
    5. await writer.drain()
    6. data = await reader.read(100)
    7. print(f'Received: {data.decode()}')
    8. writer.close()
    9. await writer.wait_closed()
    10. asyncio.run(tcp_echo_client('Hello World!'))

    异步编程实战

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

    1. 异步HTTP请求

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

    1. import aiohttp
    2. import asyncio
    3. async def fetch_url(session, url):
    4. async with session.get(url) as response:
    5. return await response.text()
    6. async def main():
    7. async with aiohttp.ClientSession() as session:
    8. html = await fetch_url(session, 'https://www.example.com')
    9. print(html[:100]) # 打印获取到的HTML内容的前100个字符
    10. asyncio.run(main())

    2. 异步文件操作

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

    1. import aiofiles
    2. import asyncio
    3. async def write_to_file(filename, content):
    4. async with aiofiles.open(filename, 'w') as f:
    5. await f.write(content)
    6. async def read_from_file(filename):
    7. async with aiofiles.open(filename, 'r') as f:
    8. content = await f.read()
    9. return content
    10. async def main():
    11. await write_to_file('example.txt', 'Hello, asyncio!')
    12. content = await read_from_file('example.txt')
    13. print(content)
    14. asyncio.run(main())

    3. 异步数据库操作

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

    1. import aiomysql
    2. import asyncio
    3. async def fetch_data(loop):
    4. conn = await aiomysql.connect(host='127.0.0.1', port=3306,
    5. user='root', password='password',
    6. db='test_db', loop=loop)
    7. async with conn.cursor() as cur:
    8. await cur.execute("SELECT 42;")
    9. (result,) = await cur.fetchone()
    10. print("Result:", result)
    11. conn.close()
    12. loop = asyncio.get_event_loop()
    13. loop.run_until_complete(fetch_data(loop))

    4. 异步Web服务器

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

    1. from aiohttp import web
    2. import asyncio
    3. async def handle(request):
    4. return web.Response(text="Hello, asyncio!")
    5. app = web.Application()
    6. app.add_routes([web.get('/', handle)])
    7. web.run_app(app)

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

  • 相关阅读:
    微信小程序
    风光储一体化能源中心 | 图扑数字孪生
    初识Java 8-1 接口和抽象类
    字体图标 icon-font
    加密货币交易所偿付能力的零知识证明
    C# 使用SIMD向量类型加速浮点数组求和运算(1):使用Vector4、Vector<T>
    【面试题精讲】Java 和 C++ 的区别?
    MCU测试科普|如何进行MCU芯片测试,具体流程是什么?
    02.从0到1,软件基础平台供应商技术团队建设例程
    JVM调优(jvisualvm,jmap、jstack、jinfo、jstat)(思维导图)
  • 原文地址:https://blog.csdn.net/qq_52213943/article/details/136631247