Python日常笔记(26)- 协程

协程-迭代器

迭代是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。

代码演示:

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】优质资源。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值