协程概念-认识asyncio
进程、线程、协程之间的关系
- 一个进程至少有一个线程,进程里面可以有多个线程
- 一个线程里面可以有多个协程
进程、线程、线程的对比
- 进程是资源分配的单位
- 线程是操作系统调度的单位
- 进程切换需要的资源最大,效率很低
- 线程切换需要的资源一般,效率一般(当然了在不考虑GIL的情况下)
- 协程切换任务资源很小,效率高
- 多进程、多线程根据cpu核数不一样可能是并行的,但是协程是在一个线程中 所以是并发
小结
-
进程、线程、协程都是可以完成多任务的,可以根据自己实际开发的需要选择使用
-
由于线程、协程需要的资源很少,所以使用线程和协程的几率最大
-
开辟协程需要的资源最少
单事件循环
# 事件循环 + 回调(驱动生成器)+ epoll(IO多路复用)
# asyncio 是python用于解决异步io编程的一整套解决方案
import time
import asyncio
async def get_html(url):
print("start get url")
await asyncio.sleep(2) # 在协程函数里面不能使用普通的time.sleep()
print("end get url")
if __name__ == '__main__':
start_time = time.time()
# 创建一个事件循环器
loop = asyncio.get_event_loop()
# 使用以下方法 传入要执行的协程函数
loop.run_until_complete(get_html("http://www.baidu.com"))
print(time.time()-start_time)
多次并发
import time
import asyncio
async def get_html(url):
print("start get url")
await asyncio.sleep(2) # 在协程函数里面不能使用普通的time.sleep()
print("end get url")
if __name__ == '__main__':
start_time = time.time()
# 创建一个事件循环器
loop = asyncio.get_event_loop()
# 创建多组任务,并发多次
tasks = [get_html("http://www.baidu.com") for i in range(10)]
loop.run_until_complete(asyncio.wait(tasks))
print(time.time()-start_time)
获取结果
import time
import asyncio
async def get_html(url):
print("start get url")
await asyncio.sleep(2) # 在协程函数里面不能使用普通的time.sleep()
print("end get url")
return "aaa"
if __name__ == '__main__':
start_time = time.time()
# 创建一个事件循环器
loop = asyncio.get_event_loop()
# 获取结果 示例一
# get_future=asyncio.ensure_future(get_html("http://www.baidu.com"))
# loop.run_until_complete(get_future)
# print(get_future.result())
# 获取结果 示例二
task = loop.create_task(get_html("http://www.baidu.com"))
loop.run_until_complete(task)
print(task.result())
print(time.time()-start_time)
获取结果
import time
import asyncio
from functools import partial # 包装函数
async def get_html(url):
print("start get url")
await asyncio.sleep(2) # 在协程函数里面不能使用普通的time.sleep()
print("end get url")
return "aaa"
def callback(url,future): # 这里接受的参数要写在最前面
print("send email to bobby")
print(url)
if __name__ == '__main__':
start_time = time.time()
# 创建一个事件循环器
loop = asyncio.get_event_loop()
# 获取结果 示例一
# get_future=asyncio.ensure_future(get_html("http://www.baidu.com"))
# loop.run_until_complete(get_future)
# print(get_future.result())
# 获取结果 示例二
task = loop.create_task(get_html("http://www.baidu.com"))
# task.add_done_callback(callback) # 在完成任务 最后再执行
task.add_done_callback(partial(callback,"http://www.baidu.com")) # 在完成任务 最后再执行 因为callback只接受函数名 如果想要传递参数需要包装处理 然后要传参数
loop.run_until_complete(task)
print(task.result())
print(time.time()-start_time)
gather和wait区别
import time
import asyncio
async def get_html(url):
print("start get url")
await asyncio.sleep(2)
print(url)# 在协程函数里面不能使用普通的time.sleep()
print("end get url")
return "aaa"
# gather 和wait区别
# gather 更加高级 可以分组
if __name__ == '__main__':
start_time = time.time()
# 创建一个事件循环器
loop = asyncio.get_event_loop()
task = [get_html("http://www.baidu.com") for i in range(10)]
#loop.run_until_complete(asyncio.wait(task))
# loop.run_until_complete(asyncio.gather(*task))
# 分组
# group1 = [get_html("http://www.baidu.com") for i in range(5)]
# group2 = [get_html("http://www.doubai.com") for i in range(5)]
# loop.run_until_complete(asyncio.gather(*group1,*group2))
#
# 也可以这样写
group1 = [get_html("http://www.baidu.com") for i in range(5)]
group2 = [get_html("http://www.doubai.com") for i in range(5)]
group1 = asyncio.gather(*group1)
group2 = asyncio.gather(*group2)
group2.cancel() # 成批取消掉任务
loop.run_until_complete(asyncio.gather(group1,group2))
print(time.time()-start_time)
task取消
import asyncio
import time
async def get_html(sleep_times):
print("waiting")
await asyncio.sleep(sleep_times)
print("done after {}s".format(sleep_times))
if __name__ == '__main__':
task1 = get_html(2)
task2 = get_html(3)
task3 = get_html(3)
tasks = [task1,task2,task3]
loop = asyncio.get_event_loop()
# 按ctrl + c 取消task
try:
loop.run_until_complete(asyncio.wait(tasks))
except KeyboardInterrupt as e:
all_tasks = asyncio.Task.all_tasks()
for task in all_tasks:
print("cancel task")
print(task.cancel())
loop.stop()
loop.run_forever()
finally:
loop.close()
一些方法
import asyncio
def callback(sleep_times):
print("sleep {} success".format(sleep_times))
# 停止事件循环
def stoploop(loop):
loop.stop()
if __name__ == '__main__':
loop = asyncio.get_event_loop()
# loop.call_soon(callback,2) # 在事件循环插入一个函数
loop.call_later(3, callback,2) # 在3秒钟后去执行这个函数
loop.call_soon(callback,4) # 优先
now = loop.time() # loop 内部时间
loop.call_at(now+2,callback,2)
# loop.call_soon(stoploop,loop) # 在事件循环插入一个函数
loop.run_forever()
借鉴链接:https://juejin.cn/post/6971037591952949256