1:yield函数
Python中的yield函数通常用于生成器generator当中,何为生成器?
在解释生成器概念前,先看一段代码观察yield函数的作用:
def fanhui(num):
while num>0:
print("当前num值:"+str(num))
yield num
num-=1
print("现在值为:"+str(num))
num = 10
p = fanhui(num)
next(p)
print('========================================')
next(p)
其运行结果如下:
当前num值:10
========================================
现在值为:9
当前num值:9
9
可以看到,我们第一次调用next函数的时候,yield后面的程序没有运行,只运行了yield前面的程序,程序在yield函数运行后中断。
在第二次调用next函数的时候,程序从断点(yield处)进行运行,然后运行到下一个yield处再次停止。也就是说,当我们每调用一次next的时候,函数中的fanhui运行从yield处运行一个循环到下一个yield处中断,且记录下当前中断位置便于下一次程序开始。
看完这个例子,相信读者已经对yield有一个初步的了解了。我们再来看下面这个例子:
def L(num):
while num>0:
yield num
num-=1
for i in L(10):
print(i)
相信读者已经能够猜出相应的运行结果了,当我们用for 循环调用L()并传入初值num=10
的时候,迭代器进入运行状态,然后在yield处返回值num给i,此时我们打印i的值。截止继续调用L()迭代器,L从上次中断的位置处继续运行,返回值9 ······
其实仔细分析一下不难看出,这不就是range(10)披了层马甲吗?对的,其实range()本质上就是一个迭代器,内部使用yield返回值的。这么做的原因是因为迭代器可以节约资源,没有必要一下子生成10个数,只需要每次调用的时候返回当前值就可以了。
可能你又要问了,for循环为啥可以调用L()/range()函数,实际上for循环进行迭代时,生成器在客户端发出请求前,不会产出任何值。在for循环中,Python隐式地在从生成器对象中获取的迭代器中调用next()。也就是说,在for循环中,Python隐式地执行以下操作:
next(L)
next(L)
next(L)
...
生成器大部分是使用yield函数的实现的,当我们调用一次生成器的时候,生成器运行到yield
处中断,返回值。下一次调用就从该yield
处开始,运行到下一个yield
处再次中断,这就是生成器的原理。
2:协程
协程 ,又称为微线程,它是实现多任务的另一种方式,只不过是比线程更小的执行单元。因为它自带CPU的上下文,这样只要在合适的时机,我们可以把一个协程切换到另一个协程。
这里有一个通俗的理解
通俗的理解:
在一个线程中的某个函数中,我们可以在任何地方保存当前函数的一些临时变量等信息,然后切换到另外一个函数中执行,注意不是通过调用函数的方式做到的
,并且切换的次数以及什么时候再切换到原来的函数都由开发者自己确定。
一个进程中可以有多个线程,一个线程中可以由多个协程,而进程和线程的切换都是在系统层面上进行的,开销较大(当然进程的切换开销更大)。而协程的切换只是单纯的操作CPU的上下文,用户可以通过yield函数方便的从一个函数切换到另外一个函数当中。
import time
def task_1():
while True:
print("调用协程1,我在前面!")
yield
print("调用协程1,我在后面!")
time.sleep(0.5)
def task_2():
while True:
print("调用协程2,我在前面!")
yield
print("调用协程2,我在后面!")
time.sleep(0.5)
if __name__ == "__main__":
t1 = task_1() # 生成器对象
t2 = task_2()
# print(t1, t2)
for _ in range(5):
next(t1)
print("\n主线程!\n") # 2、继续往下执行
next(t2)
其运行结果如下:
调用协程1,我在前面!
主线程!
调用协程2,我在前面!
调用协程1,我在后面!
调用协程1,我在前面!
主线程!
调用协程2,我在后面!
调用协程2,我在前面!
调用协程1,我在后面!
调用协程1,我在前面!
主线程!
调用协程2,我在后面!
调用协程2,我在前面!
调用协程1,我在后面!
调用协程1,我在前面!
...
从这个例子可以看出,使用yield
可以很方便的完成协程间的切换。