python中asyncio异步编程学习_python

来源:脚本之家  责任编辑:小易  

1.   想学asyncio,得先了解协程

携程的意义:

    计算型的操作,利用协程来回切换执行,没有任何意义,来回切换并保存状态 反倒会降低性能。 IO型的操作,利用协程在IO等待时间就去切换执行其他任务,当IO操作结束后再自动回调,那么就会大大节省资源并提供性能,从而实现异步编程(不等待任务结束就可以去执行其他代码

2.协程和多线程之间的共同点和区别:

共同点:

都是并发操作,多线程同一时间点只能有一个线程在执行,协程同一时间点只能有一个任务在执行;

不同点:

多线程,是在I/O阻塞时通过切换线程来达到并发的效果,在什么情况下做线程切换是由操作系统来决定的,开发者不用操心,但会造成竞争条件 (race condition) ;

协程,只有一个线程,在I/O阻塞时通过在线程内切换任务来达到并发的效果,在什么情况下做任务切换是开发者决定的,不会有竞争条件 (race condition) 的情况;多线程的线程切换比协程的任务切换开销更大;
对于开发者而言,多线程并发的代码比协程并发的更容易书写。

一般情况下协程并发的处理效率比多线程并发更高。

3. greenlet实现协程

greenlet用于创建协程,switch用于进行协程之间的切换某个协程在执行的过程中可以随时的被其他协程通过switch函数来打断,转而去执行其他协程,当前协程的中断现场会被保留,一旦中断的协程再次获得cpu的执行权首先会恢复现场然后从中断处继续执行这种机制下的协程是同步,不能并发

pip install greenlet

import time
import greenlet
 
 
def func1():
  print("func11")
  gr2.switch()
  time.sleep(1)
  print("func22")
  gr2.switch()
 
 
def func2():
  print("func33")
  gr1.switch()
  time.sleep(1)
  print("func44")
 
 
start = time.time()
gr1 = greenlet.greenlet(func1)
gr2 = greenlet.greenlet(func2)
gr1.switch()
end = time.time()
print(end - start)

4. yield关键字实现协程

def func1():
  yield 1
  yield from func2()
  yield 3
 
 
def func2():
  yield 2
  yield 4
 
 
ff = func1()
for item in ff:
  print(item)

5.gevent协程

(1)gevent实现协程

pip install gevent

from greenlet import greenlet
from time import sleep
def func1():
  print("协程1")
  sleep(2)
  g2.switch()
  print("协程1恢复运行")
 
def func2():
  print("协程2")
  sleep(1)
  g3.switch()
def func3():
  print("协程3")
  sleep(1)
  g1.switch()
 
if __name__ == '__main__':
  # 使用greenlet来创建三个协程
  g1 = greenlet(func1)
  g2 = greenlet(func2)
  g3 = greenlet(func3)
  # print(g1)
  g1.switch() # 让协程g1取抢占cpu资源

(2) gevent实现异步协程

# 协程被创建出来以后默认是多个协程同步执行
# 我们可以加入monkey补丁,把同步的协程转成异步协程
from gevent import monkey # 注意:monkey的引入必须在其他模块之前
 
monkey.patch_all() # 用monkey给整个协程队列,添加一个非阻塞I/O的补丁,使得他们成为异步协程
import time
import requests
import gevent
 
headers = {
  'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'}
 
 
def func(url, i):
  print("协程%d开启!" % i)
  res = requests.get(url=url, headers=headers)
  html = res.text
  print("协程%d执行结束,获取到的响应体大小为:%d" % (i, len(html)))
 
 
if __name__ == '__main__':
  start = time.time()
  urls = [
    "https://www.baidu.com/",
    "https://www.qq.com/",
    "https://www.sina.com.cn",
    "https://www.ifeng.com/",
    "https://www.163.com/"
  ]
  # 创建5个协程分别对上面5个网站进行访问
  g_list = []
  for i in range(len(urls)):
    g = gevent.spawn(func, urls[i], i)
    g_list.append(g)
    # func(urls[i], i)
  gevent.joinall(g_list)
  end = time.time()
  print(end - start)

6. asyncio模块实现异步协程

在python3.4及之后的版本使用,asyncio厉害之处在于:遇到IO操作时会自动切换执行其它任务

import time
import asyncio
 
 
@asyncio.coroutine
def func1():
  print(1)
  yield from asyncio.sleep(1) # 遇到IO耗时操作,自动切换到tasks中的其它任务
  print(2)
 
 
@asyncio.coroutine
def func2():
  print(3)
  yield from asyncio.sleep(1) # 遇到IO耗时操作,自动切换到tasks中的其它任务
  print(4)
 
 
tasks = [
  asyncio.ensure_future(func1()),
  asyncio.ensure_future(func2())
]
 
start = time.time()
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
end = time.time()
print(end - start)

7. asyc & await关键字实现异步编程(现在推荐使用的用法)

在python3.5及之后的版本中可以使用

import time
import asyncio
 
 
async def func1():
  print(1)
  await asyncio.sleep(1)
  print(2)
 
 
async def func2():
  print(3)
  await asyncio.sleep(1)
  print(4)
 
 
tasks = [
  asyncio.ensure_future(func1()),
  asyncio.ensure_future(func2())
]
 
start = time.time()
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
end = time.time()
print(end - start)

7.1 事件循环

    事件循环,可以把他当做是一个while循环,这个while循环在周期性的运行并执行一些任务,在特定条件下终止循环。

伪代码:

# 伪代码
任务列表 = [ 任务1, 任务2, 任务3,... ]
while True:
  可执行的任务列表,已完成的任务列表 = 去任务列表中检查所有的任务,将'可执行'和'已完成'的任务返回
  for 就绪任务 in 已准备就绪的任务列表:
    执行已就绪的任务
  for 已完成的任务 in 已完成的任务列表:
    在任务列表中移除 已完成的任务
  如果 任务列表 中的任务都已完成,则终止循环

7.2 协程和异步编程

协程函数,定义形式为 async def 的函数。

协程对象,调用 协程函数 所返回的对象。

# 定义一个协程函数
async def func():
  pass
# 调用协程函数,返回一个协程对象
result = func()

注意:调用协程函数时,函数内部代码不会执行,只是会返回一个协程对象。 

7.3 基本应用

程序中,如果想要执行协程函数的内部代码,需要 事件循环 和 协程对象 配合才能实现,如:

import asyncio
async def func():
  print("协程内部代码")
# 调用协程函数,返回一个协程对象。
result = func()
# 方式一
# loop = asyncio.get_event_loop() # 创建一个事件循环
# loop.run_until_complete(result) # 将协程当做任务提交到事件循环的任务列表中,协程执行完成之后终止。
# 方式二
# 本质上方式一是一样的,内部先 创建事件循环 然后执行 run_until_complete,一个简便的写法。
# asyncio.run 函数在 Python 3.7 中加入 asyncio 模块,
asyncio.run(result)

这个过程可以简单理解为:将协程当做任务添加到 事件循环 的任务列表,然后事件循环检测列表中的协程是否 已准备就绪(默认可理解为就绪状态),如果准备就绪则执行其内部代码。

7.4 await关键字

await是一个只能在协程函数中使用的关键字,用于遇到IO操作时挂起 当前协程(任务),当前协程(任务)挂起过程中 事件循环可以去执行其他的协程(任务),当前协程IO处理完成时,可以再次切换回来执行await之后的代码,

await + 可等待对象(协程对象、Future对象、Task对象)

示例1:await+协程对象

import asyncio
 
 
async def func1():
  print("start")
  await asyncio.sleep(1)
  print("end")
  return "func1执行完毕"
 
 
async def func2():
  print("func2开始执行")
  # await关键字后面可以跟可等待对象(协程对象、Future对象、Task对象)
  response = await func1()
  print(response)
  print("func2执行完毕")
 
 
asyncio.run(func2())

示例2: 协程函数中可以使用多次await关键字

import asyncio
 
 
async def func1():
  print("start")
  await asyncio.sleep(1)
  print("end")
  return "func1执行完毕"
 
 
async def func2():
  print("func2开始执行")
  # await关键字后面可以跟可等待对象(协程对象、Future对象、Task对象)
  response = await func1()
  print(response)
  response2 = await func1()
  print(response2)
  print("func2执行完毕")
 
 
asyncio.run(func2())

7.5 task对象

Tasks用于并发调度协程,通过asyncio.create_task(协程对象)的方式创建Task对象,这样可以让协程加入事件循环中等待被调度执行。除了使用 asyncio.create_task() 函数以外,还可以用低层级的 loop.create_task() 或 ensure_future() 函数。不建议手动实例化 Task 对象。

本质上是将协程对象封装成task对象,并将协程立即加入事件循环,同时追踪协程的状态。

注意:asyncio.create_task() 函数在 Python 3.7 中被加入。在 Python 3.7 之前,可以改用低层级的 asyncio.ensure_future() 函数。

示例1:

import asyncio
 
 
async def func():
  print(1)
  await asyncio.sleep(1)
  print(2)
  return "func的返回值"
 
 
async def main():
  print(3)
  # 创建协程,将协程封装到一个task对象中并立即添加到事件循环列表中,等待事件循环去执行,(默认是就绪状态)
  task1 = asyncio.create_task(func())
  # 创建协程,将协程封装到一个task对象中并立即添加到事件循环列表中,等待事件循环去执行,(默认是就绪状态)
  task2 = asyncio.create_task(func())
  # 当执行某协程遇到IO操作时,会自动化切换执行其他任务。
  # 此处的await是等待相对应的协程全都执行完毕并获取结果
  ret1 = await task1
  ret2 = await task2
  print(ret1, ret2)
 
 
asyncio.run(main())

示例2:用的还是比较多的

import asyncio
 
 
async def func():
  print(1)
  await asyncio.sleep(1)
  print(2)
  return "func的返回值"
 
 
async def main():
  print(3)
  # 创建协程,将协程封装到Task对象中并添加到事件循环的任务列表中,等待事件循环去执行(默认是就绪状态)。
  # 在调用
  task_list = [
    asyncio.create_task(func()),
    asyncio.create_task(func())
  ]
  # 当执行某协程遇到IO操作时,会自动化切换执行其他任务。
  # 此处的await是等待所有协程执行完毕,并将所有协程的返回值保存到done
  # 如果设置了timeout值,则意味着此处最多等待的秒,完成的协程返回值写入到done中,未完成则写到pending中。
  done, pending = await asyncio.wait(task_list, timeout=None)
  print(done)
  print(pending)
 
 
asyncio.run(main())

 示例3:

import asyncio
 
 
async def func():
  print("执行协程函数内部代码")
  # 遇到IO操作挂起当前协程(任务),等IO操作完成之后再继续往下执行。当前协程挂起时,事件循环可以去执行其他协程(任务)。
  response = await asyncio.sleep(2)
  print("IO请求结束,结果为:", response)
 
 
coroutine_list = [func(), func()]
# 错误:coroutine_list = [ asyncio.create_task(func()), asyncio.create_task(func()) ]
# 此处不能直接 asyncio.create_task,因为将Task立即加入到事件循环的任务列表,
# 但此时事件循环还未创建,所以会报错。
# 使用asyncio.wait将列表封装为一个协程,并调用asyncio.run实现执行两个协程
# asyncio.wait内部会对列表中的每个协程执行ensure_future,封装为Task对象。
done, pending = asyncio.run(asyncio.wait(coroutine_list))

总结:

在程序中只要看到asyncawait关键字,其内部就是基于协程实现的异步编程,这种异步编程是通过一个线程在IO等待时间去执行其他任务,从而实现并发。

如果是 I/O 密集型,且 I/O 请求比较耗时的话,使用协程。
如果是 I/O 密集型,且 I/O 请求比较快的话,使用多线程。
如果是 计算 密集型,考虑可以使用多核 CPU,使用多进程。

以上就是python中asyncio异步编程学习的详细内容,更多关于python中使用asyncio的资料请关注真格学网其它相关文章!

您可能感兴趣的文章:python asyncio 协程库的使用python 使用事件对象asyncio.Event来同步协程的操作

  • 本文相关:
  • python中用ggplot绘制画图实例讲解
  • python 调用pyautogui 实时获取鼠标的位置、移动鼠标的方法
  • 用python制作个论文下载器(图形化界面)
  • python中去空格函数的用法
  • python训练数据时打乱训练数据与标签的两种方法小结
  • linux中如何使用python3获取ip地址
  • django中如何防范csrf跨站点请求伪造攻击的实现
  • 完美解决pycharm无法导入包的问题 unresolved reference
  • python爬虫:通过关键字爬取百度图片
  • python 操作 elasticsearch的完整代码
  • 如何利用python asyncio编写异步爬虫
  • Python用asyncio模块做协程异步IO爬虫功能,为啥我...
  • 有专门讲python 异步,协程的书籍么
  • python异步有哪些方式
  • python 中asyncio.wait和asyncio.gather的区别
  • python编程到底好不好学?
  • Python主要要学那些课程啊?
  • python3.5 asyncio可以和aiohtttp一起使用吗
  • 现在学好python能干什么?
  • python培训需要多久?
  • 网站首页网页制作脚本下载服务器操作系统网站运营平面设计媒体动画电脑基础硬件教程网络安全vbsdos/bathtahtcpythonperl游戏相关vba远程脚本coldfusionruby专题autoitseraphzonepowershelllinux shellluagolangerlang其它首页python asyncio 协程库的使用python 使用事件对象asyncio.event来同步协程的操作python中用ggplot绘制画图实例讲解python 调用pyautogui 实时获取鼠标的位置、移动鼠标的方法用python制作个论文下载器(图形化界面)python中去空格函数的用法python训练数据时打乱训练数据与标签的两种方法小结linux中如何使用python3获取ip地址django中如何防范csrf跨站点请求伪造攻击的实现完美解决pycharm无法导入包的问题 unresolved referencepython爬虫:通过关键字爬取百度图片python 操作 elasticsearch的完整代码python入门教程 超详细1小时学会pycharm 2020最新永久激活码(附python 列表(list)操作方法详解python 元组(tuple)操作详解python 字典(dictionary)操作详解python strip()函数 介绍pycharm 使用心得(一)安装和首pycharm 2020年最新激活码(亲测python 中文乱码问题深入分析python中使用xlrd、xlwt操作excepython3 deque 双向队列创建与使用方法分儿童python练习实例python pymsql模块的使用python 和 js 有哪些相同之处在windows上安装和配置 jupyter lab 作为python操作注册表详细步骤介绍python爬虫基于lxml解决数据编码乱码问题tensorflow入门:tfrecorddataset变长数据python 正确保留多位小数的实例django单元测试工具test client使用详解
    免责声明 - 关于我们 - 联系我们 - 广告联系 - 友情链接 - 帮助中心 - 频道导航
    Copyright © 2017 www.zgxue.com All Rights Reserved