在开始介绍协程之前,咱们先了解一下迭代器和生成器,因为要学习协程,这两部分更是关键。
迭代:是访问集合元素的一种方法,迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束,迭代器只能往前不能后退。
我们可以对list,tuple,str等类型的数据使用for…in…的循环语法从其中依次拿到数据进行使用,我们把这样的过程称为遍历,也叫迭代。
如何判断是否可以迭代:
from collections import Iterable
isinstance(数据,Iterable)
如果返回值为True,则表示可以迭代。
迭代器:存储的是生成数据的方式,而不是已经生成的数据。
for temp in xxx_obj:
pass
1. 判断xxx_obj是否可以迭代
2. 在第1步成立的前提下,调用iter函数,得到xxx_obj对象的__iter__方法的返回值
3. __iter__方法的返回值 是一个迭代器
判断对象iterator是否是迭代器:
from collections import Iterator
iterator = iter(函数名)
isinstance(iterator,Iterator)
如果返回值为True,则表示对象是迭代器。
迭代器的优点:能够实现for循环,能够取里面的数据,里面存储的是生成数据的方式。而且不会占用太多的内存。
就好比python2中的range和xrange,range返回的是数据本身,xrange返回的是一个可迭代对象,python3中range也可以当成xrange用。
生成器:是一种特殊的迭代器。
创建生成器的方法:
1. nums = (x*2 for x in range(20)) # 返回的是一个可迭代对象,里面是生成数据的方法,节省空间,就是将列表的中括号变成小括号,可用for循环
2. 在函数中使用yield,那么这个函数则认为不再是函数,而是一个生成器模板,这是调用这个函数创建对象的时候,不再是调用函数,而是创建一个生成器对象。
制作一个简单的生成器案例:
def create_num(all_num):
a, b = 0, 1
current_num = 0
while current_num < all_num:
# print(a)
yield a # 如果一个函数中有yield语句,那么这个就是在是函数,而是一个生成器模板
a, b = b, a+b
current_num += 1 # 如果在调用create_num的时候,发现这个函数中有yield,那么此时,不是调用函数,而是创建一个生成器对象
obj = create_num(10)
obj2 = create_num(20)
以上就是迭代器和生成器的大致内容,而在以后的python编程中,使用最多的却是协程:gevent。
首先我们需要在电脑上安装gevent
$ pip3 install gevent
如果你没有权限,就在前面加上一个sudo就可以正确安装了。
安装好了之后,咱们就可以正常使用了。
gevent的使用:
import gevent
def f(n):
for i in range(n):
print(gevent.getcurrent(),i)
g1 = gevent.spawn(f,5)
g2 = gevent.spawn(f,5)
g3 = gevent.spawn(f,5)
g1.join()
g2.join()
g3.join()
这个就是gevent的简单使用,通过运行结果可以知道,它是一个单线程,而这个也是协程的一大优点,因为它既是一个单线程,但也可以实现多任务,它在资源调度的过程中,利用了其他协程中延时的空隙去执行其他的协程。
gevent实现多任务:
import gevent
def f(n):
for i in range(n):
print(gevent.getcurrent(),i)
gevent.sleep(0.5)
g1 = gevent.spawn(f,5)
g2 = gevent.spawn(f,5)
g3 = gevent.spawn(f,5)
g1.join()
g2.join()
g3.join()
因为gevent是一个封装好了的模块,里面有自己的延时命令,如果以后碰到了其他的延时命令,比如:
time.sleep(0.5)
这时候,这个延时命令并没有执行,需要给这段程序加个补丁:
import gevent
import time
from gevent import monkey
monkey.patch_all()
def f(n):
for i in range(n):
print(gevent.getcurrent(),i)
time.sleep(0.5)
g1 = gevent.spawn(f,5)
g2 = gevent.spawn(f,5)
g3 = gevent.spawn(f,5)
g1.join()
g2.join()
g3.join()
monkey.patch_all()这句代码会将里面的time.sleep()自动转化为gevent.sleep()命令,从而实现延时。
如果在开发过程中,需要执行的协程数量过大,我们可以通过更加简便的代码进行:
import gevent
import time
from gevent import monkey
monkey.patch_all()
def f(n):
for i in range(n):
print(gevent.getcurrent(),i)
time.sleep(0.5)
g = [g1,g2,g3]
g1 = gevent.spawn(f,5)
g2 = gevent.spawn(f,5)
g3 = gevent.spawn(f,5)
gevent.joinall(g)
这就是协程在开发过程中最后的模板。