Python49_协程再讲

greenlet的应用

import greenlet
import random
def producer():
    while True:
        item = random.randint(0,99)
        print("生成数字:%d"%item)
        c.switch(item)
def consumer():
    while True:
        item = p.switch()   #从另一个协程获得它所传递的数据
        print("消费数字:%d"%item)

if __name__ == "__main__":
    c = greenlet.greenlet(consumer)
    p = greenlet.greenlet(producer)
    c.switch()  #切换到c里面运行
    #swtich()有参数就是将参数传递给另一个协程,否则就是激活协程

gevent的应用

以后协程的实现主要用gevent

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

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

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

greenlet对yield实现了封装,gevent对greenlet再次实现了封装

代码示例(和线程非常类似):

import gevent
from gevent.queue import Queue
import random

def Consume(queue):
        while True:
            gevent.sleep(random.random())   #gevent有一个特点,遇到了延时(如此处的gevent.sleep())就切换,没有遇到延时就不切换。那么以后在网络编程中,如recv等造成的延时时,就需要用gevent里面的recv
            item=queue.get()
            print("消费者,消费:%s"%item)


def Consume2(queue):
    while True:
        gevent.sleep(random.random())   
        item = queue.get()
        print("消费者2,消费:%s" % item)

def Produce(queue):
        while True:
            gevent.sleep(random.random())
            item = random.randint(0,99)
            queue.put(item)
            print("生产者,生产:%s"%item)


def Produce2(queue):
    while True:
        gevent.sleep(random.random())
        item = random.randint(100, 199)
        queue.put(item)
        print("生产者2,生产:%s" % item)

queue = Queue(5)

p=gevent.spawn(Produce,queue)   # spawn:产卵。此时不会执行
p2=gevent.spawn(Produce2,queue)
c=gevent.spawn(Consume,queue)
c2=gevent.spawn(Consume2,queue) 
gevent.joinall([p,p2,c,c2]) #也可以通过p.join()、c.join()的方法
#

猴子补丁

作用:因为gevent要在遇到了gevent里面的延时操作时才切换,为了在不更改已有程序的基础上实现其切换,如:time.sleep(),就需要用到猴子补丁

import gevent
from gevent import monkey
import time

monkey.patch_all()  # 会自己更改代码里面的延时操作

def f1(n):
    for i in range(n):
        print(gevent.getcurrent(), i)
        time.sleep(0.5)

def f2(n):
    for i in range(n):
        print(gevent.getcurrent(), i)
        time.sleep(0.5)

def f3(n):
    for i in range(n):
        print(gevent.getcurrent(), i)
        time.sleep(0.5)

g1 = gevent.spawn(f1, 5)
g2 = gevent.spawn(f2, 5)
g3 = gevent.spawn(f3, 5)

gevent.joinall([g1, g2, g3])

协程函数(异步函数)

法一:async

#法一:
async def test1():
    print(1)
    await test2()   #test1在此等待,转去执行test2,test2执行完毕后再到此处继续执行
    print(2)
    return "haha"

async def test2():
    print(3)
    print(4)

try:
    a = test1()
    a.send(None)    #send None激活协程
except StopIteration as d:
    print(d.value)  #获得a的返回值“haha“
'''运行结果如下:
1
3
4
2
haha
'''

法二:asyncio

async def test1():
    print(1)
    await test2()   #test1在此等待,转去执行test2,test2执行完毕后再到此处继续执行
    print(2)
    return "stop"

async def test2():
    print(3)
    print(4)

import asyncio
loop = asyncio.get_event_loop()
#创建一个task类型的对象(即任务)
task = asyncio.ensure_future(test1())   #将协程变成了task类型
loop.run_until_complete(task)
print(task.result())    #获得task类型的执行结果
'''运行结果如下:
1
3
4
2
stop
'''

一次执行多个任务

async def test1():
    print(1)
    await test2()   #test1在此等待,转去执行test2,test2执行完毕后再到此处继续执行
    #await必须和async结合使用,一旦有了await,就必须有async
    print(2)
    return "stop"

async def test2():
    print(3)
    print(4)


import asyncio
loop = asyncio.get_event_loop()
tasks = [
    asyncio.ensure_future(test1()),
    asyncio.ensure_future(test1()),
    asyncio.ensure_future(test1()),
]

loop.run_until_complete(asyncio.wait(tasks))

for task in tasks:
    print(task.result())

'''运行结果如下:
1
3
4
2
1
3
4
2
1
3
4
2
stop
stop
stop
'''

添加回调函数

async def test1():
    print(1)
    await test2()   #test1在此等待,转去执行test2,test2执行完毕后再到此处继续执行
    #await必须和async结合使用,一旦有了await,就必须有awati
    print(2)
    return "stop"

async def test2():
    print(3)
    print(4)


import asyncio
loop = asyncio.get_event_loop()
 #通过回调函数获取 执行结果
def  call_back(future):
    print("回调结果:", future.result())
task = asyncio.ensure_future(test1())
task.add_done_callback(call_back)
loop.run_until_complete(task)   #loop,当成一个线程池用即可(但是并不是线程池)

'''运行结果如下:
1
3
4
2
回调结果: stop
'''
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,539评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,594评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,871评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,963评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,984评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,763评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,468评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,850评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,002评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,144评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,823评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,483评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,026评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,150评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,415评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,092评论 2 355

推荐阅读更多精彩内容

  • 参考资料 http://www.gevent.org/contents.html https://uwsgi-do...
    JunChow520阅读 16,873评论 0 10
  • 协程 阅读目录 一 引子 二 协程介绍 三 Greenlet模块 四 Gevent模块 引子 之前我们学习了线程、...
    go以恒阅读 712评论 0 1
  • 一、总体内容 1.1、协程的介绍 1.2、迭代器以及迭代器的应用 1.3、生成器(生成器与迭代器保存的都是生成数据...
    IIronMan阅读 861评论 0 1
  • 迭代、迭代器、生成器、协程、yield、greenlet、gevent、进程线程协程对比、gevent多任务图片下...
    Cestine阅读 489评论 0 0
  • 背景 The startup of you,国内译名至关重要的关系,台湾版本译名人生是永远的测试版,两个翻译各有韵...
    AkonWu阅读 539评论 0 4