Python进阶:一文搞懂迭代器生成器协程(附案例)
Posted 黑马程序员官方
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python进阶:一文搞懂迭代器生成器协程(附案例)相关的知识,希望对你有一定的参考价值。
文章目录
- 1. [重、难点]自定义迭代对象、迭代器
- 2. 迭代器案例:斐波那契数列
- 3. [重点]生成器-基本使用
- 4. 生成器案例:斐波那契数列
- 5. 生成器-使用注意
- 6. 协程-yield
- 7. 协程-greenlet
- 8. [重点]协程-gevent
- 9. 进程、线程、协程区别
- 10. 案例:并发下载器
- 11. 案例:协程版Web服务器
1. [重、难点]自定义迭代对象、迭代器
1、MyList类
1)初始化方法
2)__iter__()
方法,对外提供迭代器
3)addItem() 方法,用来添加数据2、自定义迭代器类:MyListIterator
- 初始化方法
2)迭代器方法__iter__()
- 获取下一个元素值的方法
__next__()
目标:
mylist = MyList()
for value in mylist:
print(value)
2. 迭代器案例:斐波那契数列
-
自定义了一个 Fibnacci() 迭代器
__iter__()
__next__()
-
核心思想:
a 保存第一列的值
b 保存第二列的值
-
a = b
-
b = a + b
-
取 a 的值,得到斐波那契数列
-
3. [重点]生成器-基本使用
-
生成器概念: 特殊的迭代器 (按照一定的规律生成数列)
-
生成器创建方式:
-
列表推导式
data_list2 = (x*2 for x in range(10)) print(data_list2) # 通过next获取下一个值 value = next(data_list2) print("------->", value)
-
函数中使用了 yield
# 使用yield 创建了一个生成器 def test1(): yield 10 # n 是一个生成器对象 n = test1() print(n) value = next(n) print("----->", value)
-
4. 生成器案例:斐波那契数列
-
思路:
1、创建一个生成器
目标:实现斐波那契数列
1) 定义变量保存第一列和第二列的值
2) 定义变量保存当前生成的位置3) 循环生成数据,条件(当前的列数 < 总列数) 4) 保存 a 的值 5) 修改 a \\ b 的值 (a = b, b = a+b) 6) 当前列数 + 1 7) 返回 a 的值 yield
2、定义变量保存生成器
next(生成器) 得到下一个元素值 -
yield 的作用:
# 1, 充当return 作用 # 2, 保存程序的运行状态 并且暂停程序执行 # 3, 当next 的时候,可以继续唤醒程序从yield位置继续向下执行
5. 生成器-使用注意
-
return 的作用
可以结束 生成器 的运行
-
send的作用,能唤醒生成器,也能传递参数
next(fib) 可以唤醒 生成器,但是不能传递参数
生成器.send(传递给生成器的值)
fib.send(1)
xxx = yield data # xxx = 1
6. 协程-yield
-
协程:在不开辟新的线程的基础上,实现多个任务
协程是一个特殊的生成器
-
手动实现了协程
-
work1生成器
-
work2 生成器
-
获取生成器 w1 = work1() w2 = work2()
-
协程运行起来
while True
next(w1)
next(w2)
-
7. 协程-greenlet
-
greenlet 实现协程
greenlet 是一个第三方的模块,自行的调度的微线程
-
使用步骤:
-
导入模块
from greenlet import greenlet
-
创建 greenlet 对象
g1 = greenlet(函数名)
-
切换任务
g1. switch()
-
8. [重点]协程-gevent
-
gevent 也是第三方库,自动调度协程,自动识别程序中的耗时操作
-
使用步骤:
-
导入模块
import gevent
-
指派任务
g1 = gevent.spawn(函数名, 参数1,参数2,…)
-
join() 让主线程等待协程执行完毕后再退出
g1.join
-
-
gevent 不能识别耗时操作的问题
-
替换time.sleep() —> gevent.sleep()
-
打猴子补丁
1、导入模块 from gevent import monkey
2、破解所有:monkey.patch_all()
猴子补丁的作用:
- 在运行时替换方法、属性等
- 在不修改第三方代码的情况下增加原来不支持的功能
- 在运行时为内存中的对象增加patch而不是在磁盘的源代码中增加
-
9. 进程、线程、协程区别
- 进程资源分配的基本单位、线程CPU调度的基本单位、协程单线程执行多任务
- 切换效率: 协程 > 线程 > 进程
- 高效率方式: 进程 + 协程
选择问题:
多进程:
密集CPU任务,需要充分使用多核CPU资源(服务器,大量的并行计算)的时候,用多进程。
缺陷:多个进程之间通信成本高,切换开销大。
多线程:
密集I/O任务(网络I/O,磁盘I/O,数据库I/O)使用多线程合适。
缺陷:同一个时间切片只能运行一个线程,不能做到高并行,但是可以做到高并发。
协程:
当程序中存在大量不需要CPU的操作时(IO),适用于协程;
10. 案例:并发下载器
-
案例实现思路:
1、定义要下载的图片路径
2、调用文件下载的函数,专门下载文件文件下载函数
1、根据url地址请求网络资源
2、在本地创建文件,准备保存
3、读取网络资源数据 (循环)
4、把读取的网络资源写入到本地文件中
5、做异常捕获 -
打开网址 对应的资源
urllib.request.urlopen(网址)
-
joinall() 批量把协程 添加join
joinall([协程的列表])
gevent.joinall([ gevent.spawn(download_img, img_url1, "1.gif"), gevent.spawn(download_img, img_url2, "2.gif"), gevent.spawn(download_img, img_url3, "3.gif") ])
11. 案例:协程版Web服务器
-
思路:
-
导入模块 gevent
-
创建协程 gevent.spawn()
gevent.spawn(self.request_handler, new_client_socket, ip_port) # g1.join()
-
打补丁
# 打猴子补丁, 目的:识别程序中的耗时操作 from gevent import monkey monkey.patch_all()
-
以上是关于Python进阶:一文搞懂迭代器生成器协程(附案例)的主要内容,如果未能解决你的问题,请参考以下文章