在看廖雪峰老师的python教程, 到实战部分了。
首先还是异步IO,协程。
天啊,好好理一理这些知识。
IO:IO在计算机中指Input/Output。程序和运行时的数据是在内存中驻留,由CPU这个超快的计算核心来执行,涉及到数据交换的地方(磁盘、网络等),就需要IO接口。
Input:从外面接收数据(浏览器接收新浪服务器发送的HTML;或者磁盘读取文件到内存中)
Output:往外发数据(发送数据(HTTP请求)到新浪服务器; 或者把数据写到磁盘文件里)
Stream:想象成一个水管,数据在水管里单向流动。浏览器和服务器之间需要建立两根水管,才能既发送数据,又接收数据。
CPU和内存运行速度远远高于磁盘、网络等IO。
同步IO:CPU等待IO完成完成后,再继续往下执行。
异步IO:CPU不等待IO执行完成,直接执行别的代码,等IO返回结果时,再继续处理。
异步IO明显好于同步IO。同步IO模型中,在发出IO请求到收到IO完成的时间里,主线程只能挂起。异步IO中,主线程继续在运行,即异步IO模型中,一个线程可以同时处理多个IO请求。
线程、进程:线程是最小的执行单元,而进程由至少一个线程组成。
子程序:理解成普通函数,A调用B,B调用C,C执行完毕后返回,B执行完毕后返回,最后A执行完毕。
协程:A,B协作完成程序,A执行时可以暂停下来等B,B执行一段时间后A再执行。协程不是多线程,不需要切换线程,执行效率高。
Python通过generator来实现协程。(yield)
generator:一个特殊的python对象,使用的时候才生成其他占内存的对象,可以使用next()不断获取下一个元素。generator也是可迭代对象,可以使用for循环打印。
yield:如果函数定义中包含yield
关键字,这个函数就不再是普通函数,而是一个generator。next()方法每遇到yield
就中断,等待下次执行。
然后,这个生产者消费者的例子。
第一次看没当回事儿,就以为是两个函数协作完成一项任务,没啥啊。
再需要回头看,看了好久,才理解程序运行的过程。
def consumer(): # generator
r = ''
while True:
n = yield r
if not n:
return
print('[CONSUMER] Comsuming %s...' % n)
r = '200 OK'
def produce(c):
c.send(None)
n = 0
while n < 5:
n = n + 1
print('[PEODUCE] Producing %s...' % n)
r = c.send(n)
print('[PRODUCE] Comsumer return: %s' % r)
c.close()
c = consumer()
produce(c)
c=consumer()
,consumer()函数是一个生成器,赋值给c。prodce(c)
,程序从这里开始运行。c.send(None)
,send
可以传递参数给yield表达式,修改上一个yield表达式值,这里只是启动生成器。n = 0
,变量n初始值为0,现在没有生产也没消费。while n < 5:
,循环5次。n = n + 1
,等下会作为参数传到consumer()
print('[PEODUCE] Producing %s...' % n)
,现在生产了1个。r = c.send(n)
,c.send(n)
,这里n = 1
,1作为参数替换了yield
的返回值。 然后开始执行consumer()
consumer()
中n = yield r
,1
替换了r
,然后赋值给n
,保证了consumer()
函数中n
变量和produce()
中n
变量的一致。if
语句暂时不成立,print('[CONSUMER] Comsuming %s...' % n)
,显示消费了1个。- 回到
produce()
,r = c.send(n)
:c.send()
会返回生成器下一个生成的值。consumer()
最后一行r = '200 OK'
,然后yield r
下一次会生成'200 Ok'
r
变量这时变成了'200 OK'
,print('[PRODUCE] Comsumer return: %s' % r)
,然后显示这一次生产-消费成功。while
循环五次,每次都会是这样的过程,produce()
和consumer()
中n
变量的值会保持一致,然后生产多少,就会消费多少。
程序运行结果。
======= RESTART: C:\Users\Administrator\Desktop\lxf\lxf38_Coroutine.py =======
[PEODUCE] Producing 1...
[CONSUMER] Comsuming 1...
[PRODUCE] Comsumer return: 200 OK
[PEODUCE] Producing 2...
[CONSUMER] Comsuming 2...
[PRODUCE] Comsumer return: 200 OK
[PEODUCE] Producing 3...
[CONSUMER] Comsuming 3...
[PRODUCE] Comsumer return: 200 OK
[PEODUCE] Producing 4...
[CONSUMER] Comsuming 4...
[PRODUCE] Comsumer return: 200 OK
[PEODUCE] Producing 5...
[CONSUMER] Comsuming 5...
[PRODUCE] Comsumer return: 200 OK
>>>
关键的send()
,文档说明:
generator.send(value)
The documentation on this method is convoluted:
Resumes the execution and “sends” a value into the generator function. The value argument becomes the result of the current yield expression. The send() method returns the next value yielded by the generator, or raises StopIteration if the generator exits without yielding another value.
未完待续