协程

实现单线程内函数的切换

实现协程方法

  • greenlet 早期
  • yield 生成器 保存当前状态切换至某个函数
  • asncyio装饰器 (py3.4)
  • async 、 await关键字【官方推荐】

greenlet实现协程

安装:

pip install greenlet

示例代码:

from greenlet import greenlet
def fun1()print('jhasbkjbsa') #第2 步  打印gr2.switch()  # 第 3 步  执行fun2内容print('skja')# 第6 步   打印gr2.switch() # 第 7 步  执行fun2内容def fun2()print('adad') # 第 4 步 打印gr1.switch() #第 5 步 执行fun1内容print('dsf') # 第 9 步  打印gr1 = greenlet(fun1)
gr2 = greenlet(fun2)
gr1.switch() #第 1 步  执行fun1函数内容

asyncio

import asyncio@asyncio.coroutine#装饰器   修饰函数为协程函数
def func1():print(1)yield from asyncio.sleep(2) #遇到Io耗时操作,自动化切换到tasks中的其他任务print(2)@asyncio.coroutine
def func2():print(3)yield from asyncio.sleep(2)#遇到Io耗时操作,自动化切换到tasks中的其他任务print(4)tasks = [asyncio.ensure_future( func10 ),asyncio.ensure_future( func20)]
1oop = asyncio.get_event_loop()
loop.run_unti1_complete(asyncio.wait(tasks))

注:遇到IO自动切换

关键字 async & await

import asyncioasync def func1():print(1)await asyncio.sleep(2) #遇到Io耗时操作,自动化切换到tasks中的其他任务print(2)async def func2():print(3)await asyncio.sleep(2)#遇到Io耗时操作,自动化切换到tasks中的其他任务print(4)tasks = [asyncio.ensure_future( func10 ),asyncio.ensure_future( func20)]
1oop = asyncio.get_event_loop()
loop.run_unti1_complete(asyncio.wait(tasks))

async事件循环

理解成为一个死循环,去检测并执行某些代码。

伪代码:

#伪代码任务列表=[任务1,任务2,任务3,..- ]while True:可执行的任务列表,已完成的任务列表=去任务列表中检查所有的任务,将'可执行'和'已完成'的任务返回for 就绪任务 in 可执行的任务列表:执行已就绪的任务for 已完成的任务 in 已完成的任务列表:在任务列表中移除已完成的任务如果任务列表中的任务都已完成,则终止循环
import asyncio
#去生成或获取一个事件循环
1oop = asyncio.get_event_1oop()
#将任务放到`任务列表|
loop.run_unti1_complete(任务)

协程上手

  • 协程函数 async def 函数名()

  • 协程对象 执行 协程函数 得到的对象

    async def fun():pass
    result = fun()   #内部代码不被执行  只是返回协程对象
    

执行协程函数

import asyncio
async def fun():pass
result = fun()   #内部代码不被执行  只是返回协程对象
loop = asyncio.get_event_loop()
loop.run_until_complete( result )#将内部代码交给事件循环执行

python 3.7之后也可以这样执行

import asyncio
async def fun():pass
result = fun()   #内部代码不被执行  只是返回协程对象
#loop = asyncio.get_event_loop()
#loop.run_until_complete( result )#将内部代码交给事件循环执行
asyncio.run( result )

await关键字

import asyncio
async def others():print("start"")await asyncio.sleep(2)print('end ')return '返回值"
async def func():print("执行协程函数内部代码")response1 =await Pthers()#遇到IO操作挂起当前协程(任务),等IO操作完成之后再继续往下执行。                                   当前协程挂起时,事件循环可以去执行其他协程(任务)。print("Io请求结束,结果为:",response1)response2 = await others() #  直到await全部执行完才会执行后面代码print("Io请求结束,结果为:",response2)
asyncio.run( func() )

await 等待对应值,再往下进行

Task对象

给事件循环添加多个任务。

创建task对象

py 3.7以上,建议用asyncio.create_task()

也可以使用低级版本的loop.create_task()asyncio.ensure_future()

示例:

import asyncio
async def func():print(1)await asyncio.sleep(2)print(2)return "返回值”
async def main(:print( "main开始"")task_list=[asyncio.create_task(func(),name='n1'),#name可省略asyncio.create_task(func(), name='n2')]print("main结束")#done为返回值集合  pending基本不实用done,pending = await asyncio.wait(task_1ist,timeout=None)print(done)
asyncio.run(main())

示例(task_list不写在函数里):

import asyncio
async def func():print(1)await asyncio.sleep(2)print(2)return"返回值”
task_1ist =[
func(),func()]
done, pending = asyncio.run( asyncio.wait(task_list)
print(done)

asyncio.run()会自动创建事件循环对象

等事件循环对象成功创建之后,会使列表中的函数对象自动创建成task对象


asyncio.future对象

为task的基类

示例1 :

async def mainO:
#获取当前事件循环
1oop = asyncio.get_running_1oop()
#创建一个任务(Future对象),这个任务什么都不干。
fut = 1oop.create_future()
#等待任务最终结果(Future对象),没有结果则会一直等下去。
await fut
asyncio.run( main() )

该任务执行会一直等待,等到fut被赋值为止(实际上fut在该函数不会被赋值)


示例2:

import asyncio
async def set_after(fut):await asyncio.sleep(2)fut.set_result("666")#给fut赋值 666
async def main():#获取当前事件循环1oop = asyncio_get_running_loop()#创建一个任务(Future对象),没绑定任何行为,则这个任务永远不知道什么时候结束。fut = loop.create_future()#创建一个任务(Task对象),绑定了set_after函数,函数内部在2s之后,会给fut赋值。#即手动设置future任务的最终结果,那么fut就可以结束了。await 1oop.create_task(set_after(fut) )#等待Future对象获取最终结果,否则一直等下去data = await futprint(data)
asyncio.run( main() )

concurrent.futures.Future对象

用于线程池或进程池

import time
from concurrent.futures import Future
from concurrent.futures.thread import ThreadPoo1Executor
from concurrent.futures.process import ProcessPoo1Executordef func(value):time.sleep(1)print(value)return 123
# 创建线程池
pool = ThreadPoo1Executor(max_workers=5)
# 创建进程池
#pool = ProcessPoo1Executor(max_workers=5)
for i in range(10):fut = poo1.submit(func,i)print(fut)
  • asyncio的future和线程进程池的future并无什么关联
  • 但是在一定场合,二者会交叉使用。
    • 例如:MySQL不支持协程时,IO会使用协程,而MySQL操作会用到线程和进程池。
    • 此时就会考虑到将二者future进行转换为同类,从而可以让协程得以 await

示例:

import time
import asyncio
import concurrent.futuresdef func1():#某个耗时操作time. sleep(2)return "SS"
async def main():1oop = asyncio.get_running_loop()# 1. Run in the default loop's executor(默认ThreadPoo1Executor )#第一步:内部会先调用ThreadPoolExecutor的 submit方法去线程池中申请一个线程去执行func1函数,并返回一个concurrent.futures.Future对象#第二步:调用asyncio.wrap_future将concurrent.futures.Future对象包装为asycio.Future对象。#因为concurrent.futures.Future对象不支持await语法,所以需要包装为 asycio.Future对象才能使用。fut = 1oop.run_in_executor(None,func1)#转化为线程池操作,实际返回异步的futureresult = await futprint( 'default thread poo1', result)#2.Run in a custom thread poo1 :#with concurrent.futures.ThreadPoo1Executor() as pool :#   result = await loop.run_in_executor(poo1,func1 )#print('custom thread poo1 ', result)#3. Run in a custom process poo1 :#with concurrent.futures.ProcessPoolExecutor() as pool:#   result = await loop .run_in_executor(poo1, func1 )  #print(' custom process poo1 ' , result)
asyncio.run( main() )

注释部分是使用线程进程池时应该使用的方式

-     fut = 1oop.run_in_executor(None,func1)#转化为线程池操作,实际返回异步的future

案例:

import request
import asynioasync def down1oad_image(ur1):#发送网络请求,下载图片(遇到网络下载图片的Io请求,自动化切换到其他任务)print("开始下载:",ur1)loop = asyncio.get_event_loop()#requests模块默认不支持异步操作,所以就使用线程池来配合实现了。future = loop.run_in_executor(None,requests.get, ur1)response = await futureprint('下载完成")#图片保存到本地文件file_name = ur1.rsp1it('_')[-1]with open(file_name,mode='wb') as file_object:file_object.write(response.content)
if _name__ =- '__main__":ur1_list = ['https://ww3.autoimg.cn/newsdfs/g26/MO2/35/A9/120x90_0_autohomecar__chsEe12AXQ6AOOH_AAFOCMS8nzu621.jpg','https://ww2.autoimg.cn/newsdfs/g30/M01/3C/E2/120x90_O_autohomecar__Chccsv2BBICAuntfAADj3Fd6800429.jpg','https://www3.autoimg.cn/newsdfs/g26/MOB/3c/65/120x90_0_autohomecar__chcCP12BFCmAT083AAGq7vK0sGY193.jpg']tasks = [ down1oad_image(ur1) for ur1 in ur1_list]loop = asyncio.get_event_loop()1oop.run_unti1_complete( asyncio.wait(tasks))

异步迭代器

迭代器:实现了__iter__()__next__()方法的对象

异步迭代器:实现了__aiter__()__anext__()方法的对象

import asyncioclass Reader(object):"""”自定义异步迭代器(同时也是异步可迭代对象)"""def _init__(se1f):se1f.count =0async def readline(se1f):#await asyncio.sleep(1)self.count += 1if self.count == 100:return Nonereturn self.countdef __aiter__(self):return selfasync def __anext__(self):val = await self.readline()if val == None:raise StopAsyncIterationreturn valasync def func():obj = Reader()async for item in obj:#async for只能写在协程函数中print(item)asyncio.run( func() )

异步上下文管理器

上下文管理器:实现了__enter__()方法和__exit()__方法的对象

异步上下文管理器:此种对象通过定义__aenter__()__aexit__()方法来对 async with语句中的环境进行控制。

import asyncio
class AsynccontextManager:def _init__(self):self.conn = connasync def do_something(se1f):#异步操作数据库return 666async def _ aenter__(self):#异步链接数据库self.conn = await asyncio.sleep(1)return selfasync def _aexit__(sef, exc_type,exc,tb):#异步关闭数据库链接await asyncio.sleep(1)
async def func:async with AsynccontextManagerO as f:#async with 必须写在协程函数内result = await f.do_something()print(result)
asyncio.run( func() )

替代asyncio uvloop(不支持window)

pip3 install uvloop

uvloop是事件循环的替代方案,性能高于asyncio

import asyncio
import uv1oop
asyncio.set_event_loop_policy(uv1oop.EventLoopPolicy() )
#编写asyncio的代码,与之前写的代码一致。#内部的事件循环自动化会变为uvloop
asyncio.run(...)

性能可以快至少一倍

协程学习-python相关推荐

  1. python多线程调用携程,Python 协程,Python携程

    Python 协程,Python携程 协程 进程:操作系统中存在 线程:操作系统中存在 协程:是微线程 模块(greenlet) 协程不是一个真实存在的东西,是由程序员创造出来的 协程,是对一个线程分 ...

  2. python协程学习——写个并发获取网站标题的工具

    ​ 平时做渗透的时候,有时候给的是一些域名.一些 url .一些 ip 或者三者都有,手动去一个个地打开比较浪费时间.我们需要用最短时间发现一些有趣的目标,如 xx 管理后台.于是让我们用 pytho ...

  3. python协程学习

    学习知识点: 1.知识点叫什么 2.知识点用在哪 3.知识如何实现 一. 线程.进程.协程傻傻分不清楚 1.进程 :启动多个进程 进程之间是由操作系统负责调用   线程 :启动多个线程 真正被cpu执 ...

  4. 4.19 python 网络编程和操作系统部分(TCP/UDP/操作系统概念/进程/线程/协程) 学习笔记

    文章目录 1 网络编程概念 1)基本概念 2)应用-最简单的网络通信 2 TCP协议和UDP协议进阶(网络编程) 1)TCP协议和UDP协议基于socket模块实现 2)粘包现象 3)文件上传和下载代 ...

  5. python线程池模块_python并发编程之进程池,线程池,协程(Python标准模块--concurrent.futures(并发未来))...

    需要注意一下 不能无限的开进程,不能无限的开线程 最常用的就是开进程池,开线程池.其中回调函数非常重要 回调函数其实可以作为一种编程思想,谁好了谁就去掉 只要你用并发,就会有锁的问题,但是你不能一直去 ...

  6. 协程(Python)

    目录 1.协程的优势: 2.生产者消费者协程模型 3.协程gevent实例 1.协程的优势: 协程的执行效率高.因为子程序切换不是线程切换,而是由程序自身控制.因此,没有线程切换的开销,和多线程相比, ...

  7. C++20 coroutine 探索I:co_await 原理 | 使用 C++ 协程写 python generator

    时隔三个月,才回到当时说的学协程的坑,中间学了各种各样的东西,起码对现代 C++ 有些许了解了.尾递归优化 快速排序优化 CPS 变换 call/cc setjmp/longjmp coroutine ...

  8. php swoole学习,【php】Swoole 协程学习

    第一次接触协程这个概念,是在学习Swoole时,那时看官方文档并不能完全理解协程到底是个什么东西以及该如何正确的使用它. 后来逐渐看了一些写的比较通俗的文章,加上自己的一些理解,逐步开始对协程有一些认 ...

  9. Android协程学习

    一.引入: build.gradle添加配置 kotlin{     experimental {         coroutines 'enable'     } // Coroutines   ...

最新文章

  1. java冒泡排序_Java中的经典算法之冒泡排序(Bubble Sort)
  2. OpenCASCADE可视化:应用交互服务之标准交互式对象类
  3. 机器学习手动撸代码系列3-感知机
  4. Vue模板语法---vue工作笔记0003
  5. python中print后面加逗号
  6. API 日调用量超 100 亿次!腾讯云首次披露云原生产品数据
  7. 备份表或者备份表结构
  8. 2000/XP系统蓝屏原因与解决
  9. jio tomcat_透过Jio Glass看
  10. Python分析王者峡谷中英雄信息
  11. Java中汉字生成拼音首拼和五笔码实例
  12. json rpgmv 加密_【RPG Maker MV插件编程】【实例教程6】存档的加密解密与保护
  13. 关于自动拼接地图算法
  14. 桌面视频录制软件有哪些?怎么简单又快地录制视频?
  15. 来一波PY交易吧(交换友链)
  16. 几款漂亮的Eclipse编辑器皮肤 .
  17. google news(news.google.com)重大改版
  18. 《亚马逊二十年—贝索斯的公开信》
  19. [穿衣搭配]魅惑蕾丝百变气质 - 韩式公主风
  20. 编写程序,模拟购物---学习通

热门文章

  1. SSM框架-实现Mybatis分页功能-foreknow_cms
  2. python 论文插图_插图论文
  3. ai的预览模式切换_当AI频繁切换色彩预览模式时 颜色会越变越深 求解?
  4. mysql 编辑 条目,mysql函数:将旧条目旋转到归档表
  5. laravel 与 tp5 获取控制器 方法名
  6. Matlab图像处理应用举例2
  7. centos7.2 开发 部署 .net core
  8. BootStarp的form表单的基本写法
  9. Android AES加密算法及其实现
  10. Win10无法访问Ubuntu18.04的smb解决