协程操作
一、asyncio
模块
asyncio
模块是 Python 中实现异步的一个模块,该模块在 Python3.4 的时候发布async
和 await 关键字在 Python3.5 中引入。- 因此,想要使用
asyncio
模块,建议 Python 解释器的版本不要低于 Python3.5 。
二、事件循环
- 所谓的事件循环,我们可以把它当作是一个 while 循环,这个 while 循环在循环生命周期内运行并执行一些任务,在特定的条件下结束循环。
- 在编写程序的时候可以通过如下代码来获取和创建事件循环:
import asyncio
loop = asyncio.get_event_loop()
三、协程函数和协程对象
[1]什么是协程函数
- 简单直白地将就是在一般的函数前加上
async
关键字,那这个函数就是称之为协程函数 - 其return会默认返回调用协程函数之后的协程对象
async def func():
...
[2]什么是协程对象
- 协程对象就是调用了协程函数之后返回的对象
async def func():
...
res = func()
# 会默认返回协程对象
print(res) # <coroutine object func at 0x00000230E90C82E0>
四、协程函数的应用
[1]基本应用
- 在编写程序的时候,如果想要执行协程函数内部的代码,通过 函数名() 调用函数是不可以的,需要 事件循环 和 协程对象 配合才能实现,如下代码所示:
import asyncio
# 定义协程函数
async def func():
print('这是协程函数内部!')
# 调用方法一
def main_first():
# 调用协程函数产生协程对象
res = func()
# 生成事件
loop = asyncio.get_event_loop()
loop.run_until_complete(res)
if __name__ == '__main__':
main_first()
# 这是协程函数内部!
# 调用方法二
def main_second():
res = func()
asyncio.run(res)
if __name__ == '__main__':
main_second()
# 这是协程函数1内部!
- 这个过程可以简单理解为:
- 将 协程函数 当做任务添加到 事件循环 的任务列表
- 然后事件循环检测列表中的协程函数 是否已准备就绪(默认可理解为就绪状态)
- 如果准备就绪则执行其内部代码。
[2]await
关键字
- await 是一个 只能在协程函数中使用的关键字,用于当协程函数遇到IO操作的时候挂起当前协程
- 当前协程挂起过程中,事件循环可以去执行其他的协程
- 当前协程IO处理完成时,可以再次切换回来执行 await 之后的代码
import asyncio
import os
async def write():
print('写入程序开始!')
msg = input('请输入你想要写入的信息:')
with open(os.path.join(os.path.dirname(__file__), '信息.txt'), 'a', encoding='utf-8') as fp:
fp.write(msg + '\n')
return '写入成功!'
async def func():
print('这是协程内部!')
# 等待其他任务执行
res = await write()
# 打印结果
print(res)
def main():
res = func()
asyncio.run(res)
if __name__ == '__main__':
main()
"""
这是协程内部!
写入程序开始!
请输入你想要写入的信息:123
写入成功!
"""
- 小结
- 上述的所有实例都只是创建了一个任务
- 即:事件循环的任务列表中只有一个任务
- 所以在IO等待时无法演示切换到其他任务效果。
- 在程序中想要创建多个任务对象
- 需要使用Task对象来实现。
- 上述的所有实例都只是创建了一个任务
[3]task
对象
- Tasks 用于并发调度协程
- 通过
asyncio.create_task
(协程对象) 的方式创建 Task 对象 - 这样可以让协程加入事件循环中等待被调度执行。
- 除了使用
asyncio.create_task()
函数以外 - 还可以用低层级的
loop.create_task()
或ensure_future()
函数。并且不建议手动实例化 Task 对象。 - 本质上是将协程对象封装成 Task 对象
- 并将协程立即加入事件循环,同时追踪协程的状态。
- 注意事项:
asyncio.create_task()
函数在 Python3.7 中被加入。- 在 Python3.7 之前,可以改用低层级的
asyncio.ensure_future()
函数。
(1)协程运行方式一
async.run()
运行协程async.create_task()
创建task
import asyncio
import os
async def write():
print('写入程序开始!')
msg = input('请输入你想要写入的信息:')
with open(os.path.join(os.path.dirname(__file__), '信息.txt'), 'a', encoding='utf-8') as fp:
fp.write(msg + '\n')
return '写入成功!'
async def func():
print('这是协程内部!')
# 创建协程,将协程封装到一个Task对象中并立即添加到事件循环的任务列表中,等待事件循环去执 # 行(默认是就绪状态)。
task = asyncio.create_task(write())
# 使用await等待任务完成并拿到返回值
res = await task
# 打印返回结果
print(res)
def main():
asyncio.run(func())
if __name__ == '__main__':
main()
"""
这是协程内部!
写入程序开始!
请输入你想要写入的信息:111
写入成功
"""
(2)协程运行方式二
asyncio.wait(Task对象列表,timeout)
- 将创建的Task对象放入列表中,由
asyncio.wait
统一运行 asyncio.wait
有两个返回值,前一个是完成的任务的返回值的集合,第二个是未完成的
import asyncio
import os
async def write():
print('写入程序开始!')
msg = input('请输入你想要写入的信息:')
with open(os.path.join(os.path.dirname(__file__), '信息.txt'), 'a', encoding='utf-8') as fp:
fp.write(msg + '\n')
return '写入成功!'
async def func():
print('这是协程内部!')
# 创建协程,将协程封装到一个Task对象中并立即添加到事件循环的任务列表中,等待事件循环去执行(默认是就绪状态)。
task_list = [
asyncio.create_task(write()),
asyncio.create_task(write())
]
# 使用await关键字和asyncio.wait方法等待任务完成并拿到返回值
# asyncio.wait 会返回两个参数,完成的协程返回值写入到done中,未完成则写到pending中。
# asyncio.wait 有timeout参数,如果设置了timeout值,则意味着此处最多等待的秒
done, pending = await asyncio.wait(task_list)
# 打印返回结果
print(done)
print(pending)
def main():
asyncio.run(func())
if __name__ == '__main__':
main()
r"""
这是协程内部!
写入程序开始!
请输入你想要写入的信息:11
写入程序开始!
请输入你想要写入的信息:11
{<Task finished name='Task-2' coro=<write() done,
defined at D:\project\python\project_study\网络并发\并发编程\协程.py:223> result='写入成功!'>,
<Task finished name='Task-3' coro=<write() done,
defined at D:\project\python\project_study\网络并发\并发编程\协程.py:223> result='写入成功!'>}
set()
"""
(3)获取协程返回值
async.gather()
获取返回值
import asyncio
import os
async def write():
print('写入程序开始!')
msg = input('请输入你想要写入的信息:')
with open(os.path.join(os.path.dirname(__file__), '信息.txt'), 'a', encoding='utf-8') as fp:
fp.write(msg + '\n')
return '写入成功!'
async def func():
print('这是协程内部!')
# 创建协程,将协程封装到一个Task对象中并立即添加到事件循环的任务列表中,等待事件循环去执行(默认是就绪状态)。
task_list = [
asyncio.create_task(write()),
asyncio.create_task(write())
]
# 使用await关键字和asyncio.wait方法等待任务完成并拿到返回值
# asyncio.wait 会返回两个参数,完成的协程返回值写入到done中,未完成则写到pending中。
# asyncio.wait 有timeout参数,如果设置了timeout值,则意味着此处最多等待的秒
res = await asyncio.gather(task_list[0], task_list[1])
# 打印返回结果
print(res)
def main():
asyncio.run(func())
if __name__ == '__main__':
main()
"""
这是协程内部!
写入程序开始!
请输入你想要写入的信息:11
写入程序开始!
请输入你想要写入的信息:11
['写入成功!', '写入成功!']
"""
[4]aiohttp
对象
- 我们之前学习过爬虫最重要的模块requests,但它是阻塞式的发起请求,每次请求发起后需阻塞等待其返回响应,不能做其他的事情。
- 本文要介绍的
aiohttp
可以理解成是和requests对应Python异步网络请求库,它是基于asyncio
的异步模块,可用于实现异步爬虫,有点就是更快于 requests 的同步爬虫。 - 安装方式,
pip install aiohttp
。
- 本文要介绍的
aiohttp
是一个为Python提供异步HTTP 客户端/服务端编程,基于asyncio
的异步库。asyncio
可以实现单线程并发IO操作,其实现了TCP、UDP、SSL等协议,aiohttp
就是基于asyncio
实现的http框架。
import aiohttp
import asyncio
async def main():
async with aiohttp.ClientSession() as session:
async with session.get("http://httpbin.org/headers") as response:
print(await response.text())
asyncio.run(main())
标签:__,协程,写入,async,操作,main,asyncio
From: https://www.cnblogs.com/taoyuanshi/p/18124738