python生成器 协程

生成器

参考文章:  协程   gevent

生成器进阶

看个例子:

复制代码
def gg():
    n=''
    i=0
    while True:
        n=yield i   #通过send传入到n
        if not n:
            pass
        else:
            print 'hehe',n
            i=100   #传进参数n的时候,使得i的值也变化了
        i+=1
if __name__=='__main__':
    a=gg()
    print a.send(None)
    print a.next()
    print a.send(None)
    print a.send(9)
    print a.next()
    a.close()
复制代码

结果:

/usr/bin/python2.7 /home/dahu/PycharmProjects/SpiderLearning/request_lianxi/t7.thread.4.py
0
1
2
hehe 9
101
102

可以看出

  • 生成器的send(None)方法等于next()方法,next()方法可以直接替换成for循环
  • 通过send(n)传递参数n进生成器,生成器里面通过yield关键字来获取参数的值

协程

我们利用这个特性,来学习一下协程

复制代码
#!/usr/bin/python
# coding=utf-8
# __author__='dahu'
# data=2017-
#多线程更改变量
import time
def consumer():
    r = ''
    while True:
        n = yield r
        if not n:
            return
        print('[CONSUMER] Consuming %s...' % n)
        time.sleep(0.5)
        r = '200 OK'
def produce(c):
    c.next()
    n = 0
    while n < 5:
        n = n + 1
        print('[PRODUCER] Producing %s...' % n)
        r = c.send(n)       #给生成器里传参,同时获取生成器里的值
        print('[PRODUCER] Consumer return: %s' % r)
    c.close()
if __name__=='__main__':
    c = consumer()
    produce(c)
复制代码

结果,

复制代码
/usr/bin/python2.7 /home/dahu/PycharmProjects/SpiderLearning/request_lianxi/t7.thread.4.py
[PRODUCER] Producing 1...
[CONSUMER] Consuming 1...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 2...
[CONSUMER] Consuming 2...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 3...
[CONSUMER] Consuming 3...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 4...
[CONSUMER] Consuming 4...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 5...
[CONSUMER] Consuming 5...
[PRODUCER] Consumer return: 200 OK

Process finished with exit code 0
View Code
复制代码

注意到consumer函数是一个generator(生成器),把一个consumer传入produce后:

  1. 首先调用c.next()启动生成器;

  2. 然后,一旦生产了东西,通过c.send(n)切换到consumer执行;

  3. consumer通过yield拿到消息,处理,又通过yield把结果传回;

  4. produce拿到consumer处理的结果,继续生产下一条消息;

  5. produce决定不生产了,通过c.close()关闭consumer,整个过程结束。

gevent

Python通过yield提供了对协程的基本支持,但是不完全。而第三方的gevent为Python提供了比较完善的协程支持。

gevent是第三方库,通过greenlet实现协程,其基本思想是:

当一个greenlet遇到IO操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO。

由于切换是在IO操作时自动完成,所以gevent需要修改Python自带的一些标准库,这一过程在启动时通过monkey patch完成

直接看例子:

复制代码
#!/usr/bin/python
#coding=utf-8
#__author__='dahu'
#data=2017-
from gevent import monkey; monkey.patch_all()
import gevent
import urllib2
def f(url):
    print('GET: %s' % url)
    resp = urllib2.urlopen(url)
    data = resp.read()
    print('%d bytes received from %s.' % (len(data), url))

gevent.joinall([
        gevent.spawn(f, 'https://www.cnblogs.com/dahu-daqing/'),
        gevent.spawn(f, 'https://www.liaoxuefeng.com/'),
        gevent.spawn(f, 'https://www.baidu.com/'),
])
复制代码

结果:  从结果看,3个网络操作是并发执行的,而且结束顺序不同,但只有一个线程。

复制代码
/usr/bin/python2.7 /home/dahu/PycharmProjects/SpiderLearning/request_lianxi/t10.gevent.py
GET: https://www.cnblogs.com/dahu-daqing/
GET: https://www.liaoxuefeng.com/
GET: https://www.baidu.com/
227 bytes received from https://www.baidu.com/.
38708 bytes received from https://www.liaoxuefeng.com/.
48289 bytes received from https://www.cnblogs.com/dahu-daqing/.

Process finished with exit code 0
复制代码

 

posted @   dahu1  Views(233)  Comments(0Edit  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示