协程是一种轻量级的线程,是异步编程的一种方式,允许你在程序中执行非阻塞的、并发的任务。Python 中的协程通过 async
和 await
关键字来定义,通常使用 asyncio
模块来管理和调度。
协程的定义:使用 async def
关键字定义一个协程函数。协程函数内部可以包含 await
表达式,用于等待异步操作的完成。
import asyncio
async def my_coroutine():
print("Start Coroutine")
await asyncio.sleep(1)
print("End Coroutine")
事件循环:协程需要在事件循环中运行。事件循环负责调度协程的执行,它可以通过 asyncio.get_event_loop()
获取。
loop = asyncio.get_event_loop()
运行协程:使用事件循环的 run_until_complete()
方法来运行协程。
loop.run_until_complete(my_coroutine())
-
等待操作:
await
关键字用于等待异步操作的完成,如await asyncio.sleep(1)
可以让协程暂停 1 秒。 -
协程并发:你可以同时运行多个协程,通过
asyncio.gather()
函数来汇总多个协程的执行。
async def main():
await asyncio.gather(my_coroutine(), another_coroutine())
loop.run_until_complete(main())
异步编程是一种编写非阻塞、高效、响应式应用程序的方法,通常用于处理I/O密集型操作,如网络通信、文件读写、数据库查询等。在Python中,异步编程主要借助asyncio
库,以及async
和await
关键字来实现。以下是异步编程的一些细节:
-
协程(Coroutines):协程是异步编程的核心概念。协程是一种特殊的函数,可以在执行过程中暂停,等待某些操作完成,然后再继续执行。协程使用
async def
关键字定义,内部使用await
来等待异步操作的完成。协程之间可以相互调用,形成协作式的多任务编程模型。 -
事件循环(Event Loop):事件循环是异步编程的引擎,它负责调度协程的执行。
asyncio
库提供了一个事件循环,你可以使用asyncio.get_event_loop()
来获取一个事件循环对象,并使用run_until_complete()
或run_forever()
来执行协程或运行事件循环。 -
异步操作:异步编程通常用于处理需要等待的操作,如网络请求、文件读写、数据库查询等。这些操作会被
await
关键字标记,以允许事件循环在等待操作完成时切换到其他协程,从而不阻塞主线程。 -
非阻塞操作:异步编程的目标是实现非阻塞式的操作。在异步代码中,当一个协程等待异步操作完成时,事件循环可以切换到其他协程执行,而不会阻塞整个程序。
-
多任务并发:异步编程允许同时执行多个任务,而不需要为每个任务创建一个线程或进程。这可以提高程序的效率,特别是在I/O密集型应用中。
-
回调和错误处理:异步编程通常使用回调函数来处理异步操作的结果。此外,错误处理也是重要的,你需要处理可能发生的异常,以确保应用程序的稳定性。
-
事件驱动编程:异步编程往往是事件驱动的。事件可以触发协程的执行,例如,当网络套接字准备好读取数据时,事件循环可以调用相应的协程进行处理。
-
并发性:异步编程不同于多线程编程,它通常在单个线程内处理并发任务。这减少了线程管理的开销,并使并发代码更容易编写和维护。
-
调试和测试:异步代码的调试和测试可能会更复杂一些,因为存在多个协程并发执行。Python提供了一些工具和库,如
asyncio
库中的debug
模式,以帮助调试异步代码。
模拟访问多个网址,使用协程进行并行访问
import asyncio
import time
import aiohttp
async def fetch_url(session, url):
async with session.get(url) as response:
print(f"{time.strftime('%H:%M:%S')} 访问{url} ")
return await response.text()
async def main():
urls = [
"https://www.example.com",
"https://www.baidu.com",
"https://www.python.org"
]
async with aiohttp.ClientSession() as session:
tasks = [fetch_url(session, url) for url in urls]
# gather方法是等待所有协程都完成,才返回结果
results = await asyncio.gather(*tasks)
for url, content in zip(urls, results):
print(f"URL: {url}, Length: {len(content)}")
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
执行结果:
15:14:14 访问https://www.baidu.com
15:14:14 访问https://www.python.org
15:14:15 访问https://www.example.com
URL: https://www.example.com, Length: 1256
URL: https://www.baidu.com, Length: 227
URL: https://www.python.org, Length: 50023