引言:
随着计算机硬件的不断发展,对于异步编程的需求也越来越强烈。Python中的asyncio
模块为开发者提供了一种强大而灵活的异步编程方式。本文将介绍asyncio
的基础用法,包括async/await/run语句的使用、多个协程的并发执行、以及在协程中进行网络请求的注意事项。
1. async/await/run语句介绍
在Python中,async
和await
关键字是异步编程的基础。
async
用于定义一个协程(coroutine)。
await
则用于挂起当前协程的执行,等待其他协程或异步任务完成。
run
语句是执行协程的一种方式,通过它我们可以启动一个协程并等待其完成。
import asyncio
async def example_coroutine():
print("Start Coroutine")
await asyncio.sleep(2)
print("End Coroutine")
async def main():
await example_coroutine()
asyncio.run(main())
在上述示例中,main
函数是一个协程,通过asyncio.run(main())
启动并执行,然后等待example_coroutine
协程的完成。
注意
1.await只能用于协程中,所以主函数main必须也要是async协程。
2.主函数的启动,必须使用asyncio.run,否则主程序执行完,协程也会终止。
2. 多个协程的并发执行
asyncio.gather
是一个强大的工具,可以同时运行多个协程,等待它们全部完成。与单独多次调用await
语句相比,asyncio.gather
更加简洁和高效。
import asyncio
async def foo():
print('Running in foo')
await asyncio.sleep(2) #不可使用time.sleep(2),引起是非异步函数
print("foo end")
async def foo1():
print('Running in foo11111111111')
print("foo1111111 end")
async def main():
task = asyncio.create_task(foo())
task1 = asyncio.create_task(foo1())
await asyncio.gather(task, task1)
asyncio.run(main())
在上述示例中,task1
和task2
是两个并发运行的协程任务,asyncio.gather(task1, task2)
等待它们全部完成。这种方式能更有效地利用异步并发的优势。
3. urllib.request和requests包不支持协程,只可使用aiohttp
urllib.request
和requests
是常见的HTTP请求库,但它们都是同步的,不能直接在协程中使用。为了在协程中进行网络请求,推荐使用支持异步的库,例如aiohttp
。
import aiohttp
import asyncio
async def fetch_data(url):
session = aiohttp.ClientSession()
try:
async with session.get(url) as response:
return await response.text()
finally:
await session.close()
async def main():
result1, result2 = await asyncio.gather(
fetch_data("https://example.com"),
fetch_data("https://example2.com")
)
print(result1)
print(result2)
asyncio.run(main())
在这个例子中,aiohttp
提供了异步的HTTP客户端,允许在进行网络请求时保持异步执行,从而充分发挥协程并发的优势。
4. 如果异步函数中有同步方法,会阻塞异步函数的并发。
错误案例
import time,asyncio
async def m1():
print('m1 ====== start')
time.sleep(2) # 同步函数
print('m1 ===== end')
async def m2():
print('m2 ********** start')
time.sleep(2) #同步函数
print('m2 ********* end')
async def main():
_m1 = m1()
_m2 = m2()
l1, link = await asyncio.gather(_m1, _m2)
asyncio.run(main())
可以观察到两个函数没有并发起来。
正确案例
import time,asyncio
async def m1():
print('m1 ====== start')
await asyncio.sleep(2) #注意这里,换成了异步方法
print('m1 ===== end')
async def m2():
print('m2 ********** start')
await asyncio.sleep(2) #注意这里,换成了异步方法
print('m2 ********* end')
async def main():
_m1 = m1()
_m2 = m2()
l1, link = await asyncio.gather(_m1, _m2)
asyncio.run(main())
5.同步函数和异步函数可以通过asgiref(django官方推荐)包来互相转化。
from asgiref.sync import async_to_sync,sync_to_async
且async_to_sync可以用来直接运行异步函数
asyncio.run(main())
可以使用下面的代码替代执行
async_to_sync(main)()
结论
asyncio
为Python提供了一种强大的异步编程方式,通过async
、await
、run
等语句,以及asyncio.gather
的使用,我们能够轻松实现并发执行的异步任务。在进行网络请求时,选择支持异步的库(如aiohttp
)是确保协程异步性能的关键。希望通过本文的介绍,读者能够更好地理解和运用asyncio
进行异步编程。