当前位置: 首页 > 后端技术 > Python

9.迭代器、生成器和协程

时间:2023-03-25 20:36:07 Python

1.迭代器什么是迭代器?迭代器是一个记住遍历位置的对象。迭代器对象从集合的第一个元素开始访问,直到访问完所有元素。只能前进不能后退。什么是iterable(可迭代对象)?1.遵循可迭代协议的对象2.可迭代协议实现了iter()方法,返回的Iterator对象本身实现了next()方法。当调用next()方法时,返回下一个值,直到无法访问到任何值。列表、元组等是可迭代对象。我们可以通过iter()函数获取这些可迭代对象的迭代器,然后使用next()函数获取下一条数据。iter()函数实际上调用了__iter_In[5]:list_demo=[iforiinrange(10)]In[6]:iter_list=iter(list_de)In[7]:iter_list=iter(list_demo)In[8]:next(iter_list)Out[8]:0In[9]:next(iter_list)Out[9]:1In[10]:next(iter_list)Out[10]:22.生成器什么是生成器?当我们使用列表的时候,列表是已经定义好的数据,比如[1,2,3,4,5,6,7,8],这个可以按照一定的算法计算出后面的元素,是否可以不创建整个列表,而不是在遍历循环时,根据算法计算元素然后使用,这样可以节省大量空间。实现这个需求的生成器(Generator)本质上是迭代器,只是一种特殊的迭代器。生成器是一种特殊的迭代器。生成器和普通函数的区别在于使用yield而不是return来返回值。使用()和理解定义生成器In[14]:list_demo=[iforiinrange(10)]In[15]:type(list_demo)Out[15]:listIn[16]:generator_demo=(iforiinrange(10))In[17]:type(generator_demo)Out[17]:generator使用函数实现defa():forxinrange(3):print(x)yieldm=a()forxinrange(3):next(m)3.协程协程不是进程,也不是线程,它是一种通过用户空间调度完成的并发处理方式。它是python中实现多任务的另一种方式,但是比线程更小,占用的执行单元更小。为什么叫执行单元,因为它有自己的CPU上下文。这样我们就可以在合适的时候将一个协程切换到另一个协程。只要在此过程中保存或恢复了CPU上下文,程序仍然可以运行。协程在线程内调度,不需要更多的线程,自然也就没有多线程切换带来的开销。协程是非抢占式调度。只有当一个协程自愿放弃控制时,才能调度另一个协程。协程不需要使用锁机制,因为它是在同一个线程中执行的。协程的简单实现defa():forxinrange(3):print(x)yielddefb():forxinrange(3):print(x)yieldm=a()n=b()forxinrange(3):next(m)next(n)通过线程中的generator完成调度,这样两个函数执行的差不多了。这样的调度不是由操作系统的进程或线程完成的,而是由用户自己设计的,这就是协程。Greenlet实现协程fromgreenletimportgreenletimporttimedeftest1():whileTrue:print("---test1---")g2.switch()time.sleep(0.5)deftest2():whileTrue:print("---test2---")g1.switch()time.sleep(0.5)g1=greenlet(test1)g2=greenlet(test2)#切换到g1运行g1.switch()gevent比greenlet更强大,可以自动切换示例1importgeventdeffun(n):forxinrange(n):print(gevent.getcurrent(),x)gevent.sleep(1)g1=gevent.spawn(fun,5)#第一个参数为传递的执行函数,第二个参数,是f的参数g2=gevent.spawn(fun,5)g3=gevent.spawn(fun,5)g1.join()g2.join()g3.join()例子2fromgeventimportmonkeyimportgeventimportrandomimporttimemonkey.patch_all()defcoroutine_work(coroutine_name):foriinrange(10):print(coroutine_name,i)time.sleep(random.random())gevent.joinall([gevent.spawn(coroutine_work,"work1"),gevent.spawn(coroutine_work,"work2")])示例3fromgeventimportmonkeyimportgeventimport随机导入时间从gevent.poolimportPoolpool=Pool(5)#限制发送协程数monkey.patch_all()#defcoroutine_work(coroutine_name):foriinrange(10):print(coroutine_name,i)time.sleep(random.random())gevent.joinall([pool.spawn(coroutine_work,coroutine_name='work1'),pool.spawn(coroutine_work,coroutine_name='work2'),])