Python的asyncio
模块是用于编写单线程并发代码的库,使用协程,事件循环,协议和任务。
用一个日常例子来解释:假如现在有一个烧水泡面任务。
- 同步操作:拆方便面包装的准备工作1分钟,开始烧水,干等水开5分钟,再注水。一共6分钟完成任务。
- 异步操作:开始烧水,拆方便面包装的准备工作1分钟,刷dy 4分钟,水开了注水。全程耗时4分钟,还多刷了4分钟dy。血赚
- 异步任务的时长取决于最慢的那一个操作的时间。因为在等待期间,会自动切换到可执行的任务上,而不是干巴巴的等待。
- 即为“统筹运算”,所以异步提升了程序运行效率和极限的压榨单个线程的利用率。
- 所以如何让单个线程可以在多个任务中自由切换就是异步编程的关键。
下面是一些使用async
和await
关键字的示例代码,可以帮助你开始学习异步编程:
1. 简单的异步函数示例:
import asyncio
async def main():
print('Hello')
# 在异步中,使用此方法来实现异步等待。而不是time.sleep这种傻乎乎的干等
# 所有异步操作前都需要加 await 关键字。
await asyncio.sleep(1)
print('World')
asyncio.run(main())
2. 同时运行多个异步函数:
import asyncio
async def say_after(delay, what):
await asyncio.sleep(delay)
print(what)
async def main():
task1 = asyncio.create_task(say_after(1, 'Hello'))
task2 = asyncio.create_task(say_after(2, 'World'))
await task1
await task2
asyncio.run(main())
3. 使用asyncio.gather
来同时运行多个异步函数:
import asyncio
async def task1():
await asyncio.sleep(2)
return "Task1 completed"
async def task2():
await asyncio.sleep(1)
return "Task2 completed"
async def main():
results = await asyncio.gather(task1(), task2())
for result in results:
print(result)
asyncio.run(main())
这些示例代码展示了Python异步编程的一些基本概念和结构。
在Python中,你可以使用aiohttp
库来执行异步的HTTP请求。首先,确保你已经安装了该库,你可以使用以下命令进行安装:
pip install aiohttp
4. 下面是一个使用aiohttp
库的简单示例代码:
import aiohttp
import asyncio
async def fetch(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(session, 'http://python.org')
print(html[:200]) # 打印获取到的网页内容的前200个字符
# 运行主函数
asyncio.run(main())
- 定义了一个
fetch
异步函数,它使用aiohttp.ClientSession
来执行异步的GET
请求。 - 定义了一个
main
异步函数,它创建了一个aiohttp.ClientSession
实例,并调用了fetch
函数来获取网页的内容。 - 使用
asyncio.run
函数来运行main
函数。
5. 异步爬虫,批量获取多个URL的内容:
import aiohttp
import asyncio
async def fetch_content(url, session):
async with session.get(url) as response:
return await response.text()
async def main():
urls = [
'http://python.org',
'https://www.wikipedia.org/',
'https://www.google.com/'
]
async with aiohttp.ClientSession() as session:
# 创建一个异步的任务列表
tasks = [fetch_content(url, session) for url in urls]
responses = await asyncio.gather(*tasks)
for resp in responses:
print(resp[:200]) # 打印获取到的网页内容的前200个字符
asyncio.run(main())
常用的响应对象方法和属性:
response.status
: 响应的HTTP状态码。
response.headers
: 包含响应头的映射。
response.text()
: 异步方法,用于获取响应体作为字符串。
response.json()
: 异步方法,用于解析响应体中的JSON内容。
response.read()
: 异步方法,用于获取响应体的原始字节。
response.cookies
: 包含响应中的cookies的映射。
6. 异步读写文件(使用aiofiles
模块,需要首先安装):
pip install aiofiles
import aiofiles
import asyncio
async def read_file(file_path):
async with aiofiles.open(file_path, 'r') as f:
content = await f.read()
return content
async def write_to_file(file_path, content):
async with aiofiles.open(file_path, 'w') as f:
await f.write(content)
async def main():
content = await read_file('path/to/your/input/file.txt')
await write_to_file('path/to/your/output/file.txt', content)
asyncio.run(main())
把介绍概念放在最后。
- 事件循环
tasks
- 类似于一个列表,我们在创建一些协程任务的时候,会将任务放到事件循环中。事件循环会对当前存在的任务进行状态的判断。对已经完成的任务会进行删除,如果是未完成的任务/等待执行的任务会被事件循环调度
- 如果当前事件循环中的任务已经全部完成,则事件循环列表为空。如果为空,则中断循环并退出。
- 协程
async
- 通过
async
关键字装饰的程序是一个协程函数。如果一个协程函数后存在(),返回一个协程对象。
- 通过
task
对象- 一个协程对象可以原生进行任务的挂起
furure
对象- 类似于
task
对象,task
对象其实是future
对象的一个子类
- 类似于
async
/await
关键字async
用于定义协程函数的,await
是用于挂起堵塞协程任务的。