python协程 02/28

协程

协程,又称微线程,纤程。英文名Coroutine。
协程是程序级别的由程序根据需要自己调度。在一个线程中会有很多函数,我们把这些函数称为子程序,在子程序执行过程中可以中断去执行别的子程序,而别的子程序也可以中断回来继续执行之前的子程序,这个过程就称为协程。也就是说在同一线程内一段代码在执行过程中会中断然后跳转执行别的代码,接着在之前中断的地方继续开始执行,类似与yield操作。
协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。
协程的优点:
  (1)无需线程上下文切换的开销,协程避免了无意义的调度,由此可以提高性能(但也因此,程序员必须自己承担调度的责任,同时,协程也失去了标准线程使用多CPU的能力)
  (2)无需原子操作锁定及同步的开销
  (3)方便切换控制流,简化编程模型
  (4)高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理。
协程的缺点:
  (1)无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上.当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。
  (2)进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序

协程的实现方式

(1)yield实现协程效果

def a():
    print("进入a方法")
    bone = yield#接受send发送的数据
    print(bone)
    print("结束a方法")
def b(aa):
    aa.send(None)
    print("进入b方法")
    aa.send("一个包子")
def work():
    aa = a()
    b(aa)
work()

(2)greenlet模块实现程序间切换执行

import greenlet
def A():
    print("a.....")
    g2.switch()
    print("a....2")
    g2.switch()
def B():
    print("b.....")
    g1.switch()
    print("b....2")
    g1.switch()
g1 = greenlet.greenlet(A)
g2 = greenlet.greenlet(B)
g1.switch()

(3)gevent实现协程
gevent 是一个第三方库,在gevent中用到的主要模式是greenlet, 它是以C扩展模块形式接入Python的轻量级协程。 greenlet全部运行在主程序操作系统进程的内部,但它们被协作式地调度。gevent会主动识别程序内部的IO操作,当子程序遇到IO后,切换到别的子程序。如果所有的子程序都进入IO,则阻塞。
1.事件:
事件是一个可以让我们在Greenlet之间异步通信的形式

import gevent
from gevent.event import Event
evt = Event()
def setter():
    print('A: Hey wait for me, I have to do something')
    gevent.sleep(3)
    print("Ok, I'm done")
    evt.set()
def waiter():
    print("I'll wait for you")
    evt.wait()  # blocking
    print("It's about time")

def main():
    gevent.joinall([
        gevent.spawn(setter),
        gevent.spawn(waiter),
        gevent.spawn(waiter),
    ])
if __name__ == '__main__': main()
import gevent
from gevent.event import AsyncResult#Event有一个扩展AsyncResult(异步),可以在set的时候带上数据传递给各waiter去get
a = AsyncResult()
def setter():
    gevent.sleep(3)
    a.set('Hello!')
def waiter():
    print(a.get())
gevent.joinall([
    gevent.spawn(setter),
    gevent.spawn(waiter),
])

2.队列:
队列是一个排序的数据集合,它有常见的put / get操作, 但是它是以在Greenlet之间可以安全操作的方式来实现的。
举例来说,如果一个Greenlet从队列中取出一项,此项就不会被同时执行的其它Greenlet再取到了。

import gevent
from gevent.queue import Queue

tasks = Queue()

def worker(n):
    while not tasks.empty():
        task = tasks.get()
        print('Worker %s got task %s' % (n, task))
        gevent.sleep(0)
    print('Quitting time!')

def boss():
    for i in range(1,25):
        tasks.put_nowait(i)

gevent.spawn(boss).join()

gevent.joinall([
    gevent.spawn(worker, 'steve'),
    gevent.spawn(worker, 'john'),
    gevent.spawn(worker, 'nancy'),
])

3.Group/Pool gevent文档翻译为组合池:
组(group)是一个运行中greenlet的集合,集合中的greenlet像一个组一样 会被共同管理和调度。
它也兼饰了像Python的multiprocessing库那样的 平行调度器的角色。

import gevent
from gevent.pool import Group

def talk(msg):
    for i in range(3):
        print(msg)

g1 = gevent.spawn(talk, 'bar')
g2 = gevent.spawn(talk, 'foo')

group = Group()
group.add(g1)
group.add(g2)
group.join()

print("主线程")

这里使用了group.map()这个函数来取得各spawn的返回值。map()是由第二个参数控制迭代次数,并且传递给第一个参数值而运行的。拿这个函数举例,这里会返回一个list构成这个list的对象就是将迭代的参数传进函数运行之后的返回值。这里得到的结果是[0, 1, 2]

from gevent import getcurrent
from gevent.pool import Group

group = Group()
def hello_from(n):
    print('Size of group %s' % len(group))
    print('Hello from Greenlet %s' % id(getcurrent()))
    return n

x = group.map(hello_from, range(3))
print (type(x))
print (x)

map返回list对象,而imap返回一个iterable对象
这里运行的时候,会将并行控制到3个,执行也是每2秒执行3个,而不是不设置的时候2秒之后将输出所有的结果。

import gevent
from gevent.pool import Group

def intensive(n):
    gevent.sleep(3 - n)
    return 'task', n

print('Ordered')
ogroup = Group()
x = ogroup.imap(intensive, range(3))
print (x)

for x in ogroup.imap(intensive, range(3)):
    print (x)

先返回的先回来,这个如果是imap运行的话,会先等上3秒钟开始返回0然后1 2 一次返回。

Pool对象

Group是Pool类的父类。pool是可以指定池子里面最多可以拥有多少greenlet在跑而且申明也很简单

from gevent.pool import Pool
x = Pool(10)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值