协程-迭代器
迭代是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
代码演示:
import time
class MyList(object):
def __init__(self):
self.list1 = list()
# 定义一个迭代数据的下标
self.index = 0
def add(self, name):
self.list1.append(name)
# 想要某一个类有迭代(Iterable)功能必须有__iter__方法
def __iter__(self):
# 返回的类必须要有__iter__方法和__next__方法才可以真正迭代
return self
def __next__(self):
time.sleep(1)
if self.index < len(self.list1):
# 迭代的数据
data = self.list1[self.index]
# 迭代之后将下标自增1
self.index += 1
return data
else:
# 抛出此异常迭代器就终止
raise StopIteration
if __name__ == "__main__":
myList = MyList()
myList.add("zhangsan")
myList.add("lisi")
myList.add("wangwu")
myList.add("zhaoliu")
for name in myList:
print(name)
注意:想要某一个类有迭代(Iterable)功能必须有__iter__方法,并且该方法的返回值(类)必须要有__iter__方法和__next__方法才可以真正迭代。
判断一个对象是否可以迭代
可以使用 isinstance() 判断一个对象是否是 Iterable 对象
可以使用 isinstance() 判断一个对象是否是 Iterator 对象
代码:
print(isinstance(myList, collections.Iterable))
print(isinstance(myList, collections.Iterator))
用迭代器实现斐波拉契
# 迭代器方式斐波拉契
class Feibolaqi(object):
def __init__(self, num):
self.num = num
self.count = 0
self.x = 0
self.y = 1
def __iter__(self):
return self
def __next__(self):
if self.count < self.num:
self.x, self.y = self.y, self.x + self.y
self.count += 1
return self.x
else:
raise StopIteration
if __name__ == "__main__":
for num in Feibolaqi(10):
print(num)
生成器
使用了yield关键字的函数不再是函数,而是生成器。(使用了yield的函数就是生成器)
yield关键字有两点作用:
1.保存当前运行状态(断点),然后暂停执行,即将生成器(函数)挂起
2.将yield关键字后面表达式的值作为返回值返回,此时可以理解为起到了return的作用
可以使用next()函数让生成器从断点处继续执行,即唤醒生成器(函数)
Python3中的生成器可以使用return返回最终运行的返回值,而Python2中的生成器不允许使用return返回一个返回值(即可以使用return从生成器中退出,但return后不能有任何表达式)。
使用yield方式实现斐波拉契
def yieldFeibolaqi():
a = 0
b = 1
count = 0
while count < 10:
# 在此处将停顿,并且将值传递给调用next方法处
yield a
a, b = b, a + b
count += 1
if __name__ == "__main__":
fei = yieldFeibolaqi()
while True:
try:
a = next(fei)
print(a)
except:
break
使用yield实现多任务代码
import time
def yieldduorenwu1():
count = 0
while count < 10:
print("==========yieldduorenwu1==========")
# 在此处将停顿
yield
time.sleep(1)
def yieldduorenwu2():
count = 0
while count < 10:
print("==========yieldduorenwu2==========")
# 在此处将停顿
yield
time.sleep(1)
if __name__ == "__main__":
duo1 = yieldduorenwu1()
duo2 = yieldduorenwu2()
while True:
next(duo1)
next(duo2)
协程gevent使用
首先安装gevent(windows版本)
1、下载,我的电脑为window10
2、把该文件下载到python安装的根目录下,我的安装目录为C:\Users\Administrator\AppData\Local\Programs\Python\Python37。
3、在该安装目录下运行python get-pip,cmd显示为C:\Users\Administrator\AppData\Local\Programs\Python\Python37>python get-pip.py
下载成功后继续在python安装目录下执行: pip install gevent
然后pychar中就自动加载了
gevent来完成多任务
代码:
import gevent
import time
from gevent import monkey
# 有耗时操作时需要
monkey.patch_all() # 将程序中用到的耗时操作的代码,换为gevent中自己实现的模块
def f1(n):
for i in range(n):
print(gevent.getcurrent(), i)
# 必须延时才会显现多任务的效果
time.sleep(0.1)
def f2(n):
for i in range(n):
print(gevent.getcurrent(), i)
# 必须延时才会显现多任务的效果
time.sleep(0.1)
def f3(n):
for i in range(n):
print(gevent.getcurrent(), i)
# 必须延时才会显现多任务的效果
time.sleep(0.1)
gevent.joinall([
gevent.spawn(f1, 2),
gevent.spawn(f2, 2),
gevent.spawn(f3, 2)
])
总结
进程是资源分配的单位
线程是操作系统调度的单位
进程切换需要的资源很最大,效率很低
线程切换需要的资源一般,效率一般(当然了在不考虑GIL的情况下)
协程切换任务资源很小,效率高
多进程、多线程根据cpu核数不一样可能是并行的,但是协程是在一个线程中 所以是并发
作者:阿超
原创公众号:『Python日常笔记』,专注于 Python爬虫等技术栈和有益的程序人生,会将一些平时的日常笔记都慢慢整理起来,也期待你的关注和阿超一起学习,公众号回复【csdn】优质资源。