热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Python高级编程技巧协程

先来说几个概念同步:代码调用IO操作时,必须等到操作完成返回的调用方式,同步是并行异步:代码调用IO操作时,必

先来说几个概念
同步: 代码调用IO操作时,必须等到操作完成返回的调用方式,同步是并行
异步: 代码调用IO操作时,必须等到操作完成返回的调用方式,异步是串行
阻塞: 从调用者的角度说,如果调用时被卡住,不再往下执行,需要等待就是说阻塞
非阻塞: 从调用者的角度说,如果调用时没有被卡住,继续往下执行无需等待就是说非阻塞


生成器—send方法


  1. 启动生成器
  2. 发送值给生成器返回

def generator(num):a, b &#61; 0, 1con &#61; 0while con < num:result &#61; yield a # 先执行右边&#xff0c;会阻塞在这里print(&#39;result>>&#39;, result)a, b &#61; b, a &#43; bcon &#43;&#61; 1return 123g &#61; generator(5)
g.close() # 关闭生成器&#xff0c;后续的值将取不了
# send 方法可以启动生成器都是第一次传的值必须是空
print(next(g)) # 这也可以取出来
print(g.send(&#39;huran&#39;))for i in g: # 还可以用for循环print(i, end&#61;&#39;-&#39;)
# 捕获生成器的返回值
while True:try:ret &#61; next(g)print(ret)except Exception as e:print(e.value)break

在这里插入图片描述


yield完成多任务

利用就是yield会阻塞的特性

import timedef task1():while True:print("--1--")time.sleep(0.1)yielddef task2():while True:print("--2--")time.sleep(0.1)yielddef main():t1 &#61; task1()t2 &#61; task2()while True:next(t1)next(t2)if __name__ &#61;&#61; "__main__":main()

yield from

chain&#xff08;&#xff09;可传入多个可迭代的对象&#xff0c;对他们进行一个for循环取出值来。

lis &#61; [1, 2, 3]
dis &#61; {&#39;name&#39;: &#39;juran&#39;,&#39;age&#39;: 18
}def my_chian(*args, **kwargs):for val in args:yield from valfor value in my_chian(lis, dis):print(value)

yield from

def generator_1(): # 子生成器total &#61; 0while True:x &#61; yieldprint(&#39;加&#39;, x)if not x: breaktotal &#43;&#61; xreturn totaldef generator_2(): # 委托生成器while True:total &#61; yield from generator_1() # 子生成器print(&#39;加和总数是:&#39;, total)def main(): # 调用方# g1 &#61; generator_1()# g1.send(None)# g1.send(2)# g1.send(3)# g1.send(None)g2 &#61; generator_2()g2.send(None)g2.send(2)g2.send(3)g2.send(None)if __name__ &#61;&#61; &#39;__main__&#39;:main()

【子生成器】&#xff1a;yield from后的generator_1()生成器函数是子生成器
【委托生成器】&#xff1a;generator_2()是程序中的委托生成器&#xff0c;它负责委托子生成器完成具体任务。
【调用方】&#xff1a;main()是程序中的调用方&#xff0c;负责调用委托生成器。


协程

协程&#xff0c;又称微线程
协程是python个中另外一种实现多任务的方式&#xff0c;只不过比线程更小占用更小执行单元&#xff08;理解为需要的资源&#xff09;
Python中的协程大概经历了如下三个阶段&#xff1a;


  1. 最初的生成器变形yield/send
  2. yield from
  3. 在最近的Python3.5版本中引入async/await关键字

协程的实现

from greenlet import greenlet
import timedef greenlet_1():while True:print(&#39;--1--&#39;)g2.switch()time.sleep(0.5)def greenlet_2():while True:print(&#39;--2--&#39;)g1.switch()time.sleep(0.5)g1 &#61; greenlet(greenlet_1)
g2 &#61; greenlet(greenlet_2)
g1.switch()

gevent实现多任务
遇到等待会自动切换到另外一个任务

import gevent
from gevent import monkey
monkey.patch_all() # 将所用的噩耗时操作换为gevent模块的def test1(n):for i in range(n):print(gevent.getcurrent(), i)gevent.sleep(0.5) # 这里会有等待&#xff0c;会自动在上一步自动切换到另外一个def test2():while True:print(gevent.getcurrent(), &#39;---2---&#39;)gevent.sleep(0.5) # 这里会有等待&#xff0c;会自动在上一步自动切换到另外一个t1 &#61; gevent.spawn(test1, 2) # 第一个参数是对象&#xff0c;第二个是参数&#xff08;传入函数中的&#xff0c;可有可无&#xff09;
t2 &#61; gevent.spawn(test2)
t1.join() # 要等到执行完毕&#xff0c;否则直接到这里
t2.join()

案例&#xff1a;

import gevent
from gevent import monkey
monkey.patch_all()
import requestsdef download(url):print("get:%s" % url)ret &#61; requests.get(url)data &#61; ret.textprint(len(data), ret)g1 &#61; gevent.spawn(download, &#39;https://www.kancloud.cn/ju7ran/gaoji/1474878&#39;)
g2 &#61; gevent.spawn(download, &#39;https://fanyi.baidu.com/?fr&#61;websearch_submit&pid&#61;sogou__free#pt/zh/%3CGreenlet&#39;)
g1.join()
g2.join()
访问的网站并不是按照你写的顺序来执行完成的&#xff0c;而是先执行完时间短一点的&#xff0c;

总结&#xff1a;
进程是资源分配的基本单位
线程是操作系统调度和执行的单位
进程切换需要的资源很最大&#xff0c;效率很低
线程切换需要的资源一般&#xff0c;效率一般&#xff08;当然了在不考虑GIL的情况下&#xff09;
协程切换任务资源很小&#xff0c;效率高
多进程、多线程根据cpu核数不一样可能是并行的&#xff0c;但是协程是在一个线程中 所以是并发


推荐阅读
author-avatar
手机用户2602920093
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有