python协程

协程

  • 通常在Python中我们进行并发编程一般都是使用多线程或者多进程来实现的,对于计算型任务由于GIL的存在我们通常使用多进程来实现,而对与IO型任务我们可以通过线程调度来让线程在执行IO任务时让出GIL,从而实现表面上的并发。

  • 其实对于IO型任务我们还有一种选择就是协程,协程是运行在单线程当中的“并发”,协程相比多线程一大优势就是省去了多线程之间的切换开销,获得了更大的运行效率。Python中的asyncio也是基于协程来进行实现的。在进入asyncio之前我们先来了解一下Python中怎么通过生成器进行协程来实现并发。

yield实现

  • 只要在def中有yield关键字的 就称为 生成器
  • next()函数让生成器从断点处继续执行,即唤醒生成器(函数)
import time

def demo1():
    while True:
        print("----111-demo1--")
        yield
        time.sleep(0.5)

def demo2():
    while True:
        print("----222-demo2--")
        yield
        time.sleep(0.5)

def main():
    d1 = demo1()
    d2 = demo2()
    while True:
        next(d1)
        next(d2)

if __name__ == "__main__":
    main()
# output
----111-demo1--
----222-demo2--
----111-demo1--
----222-demo2--
----111-demo1--
----222-demo2--
----111-demo1--
----222-demo2--
...

greenlet实现


from greenlet import greenlet
import time

def test1():
    while True:
        print "---A--"
        gr2.switch()
        time.sleep(0.5)

def test2():
    while True:
        print "---B--"
        gr1.switch()
        time.sleep(0.5)

gr1 = greenlet(test1)
gr2 = greenlet(test2)

#切换到gr1中运行
gr1.switch()

# output
---A--
---B--
---A--
---B--
---A--
---B--
---A--
---B--
...

gevent实现

  • greenlet已经实现了协程,但是这个还的人工切换,是不是觉得太麻烦了,不要捉急,python还有一个比greenlet更强大的并且能够自动切换任务的模块gevent

  • 其原理是当一个greenlet遇到IO(指的是input output 输入输出,比如网络、文件操作等)操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。

  • 由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO

import gevent

def demo(n):
    for i in range(n):
        print(gevent.getcurrent(), i)
        # 这里延迟操作需要调用gevent的sleep
        # 若没有I/O操作,gevent不会切换协程
        gevent.sleep(0.5)
        
# spawn 第一个参数是调用的函数名, 第二个参数是传入的参数
g1 = gevent.spawn(demo, 3)
g2 = gevent.spawn(demo, 5)
g3 = gevent.spawn(demo, 2)
g1.join()
g2.join()
g3.join()

# output
<Greenlet "Greenlet-0" at 0x1cabed4f448: demo(3)> 0
<Greenlet "Greenlet-1" at 0x1cabed4f548: demo(5)> 0
<Greenlet "Greenlet-2" at 0x1cabed4f648: demo(2)> 0
<Greenlet "Greenlet-0" at 0x1cabed4f448: demo(3)> 1
<Greenlet "Greenlet-1" at 0x1cabed4f548: demo(5)> 1
<Greenlet "Greenlet-2" at 0x1cabed4f648: demo(2)> 1
<Greenlet "Greenlet-0" at 0x1cabed4f448: demo(3)> 2
<Greenlet "Greenlet-1" at 0x1cabed4f548: demo(5)> 2
<Greenlet "Greenlet-1" at 0x1cabed4f548: demo(5)> 3
<Greenlet "Greenlet-1" at 0x1cabed4f548: demo(5)> 4

from gevent import monkey
import gevent
import random
import time

# 有耗时操作时需要
monkey.patch_all()  # 将程序中用到的耗时操作的代码,换为gevent中自己实现的模块

def coroutine_work(coroutine_name):
    for i in range(10):
        print(coroutine_name, i)
        time.sleep(random.random())

gevent.joinall([
        gevent.spawn(coroutine_work, "work1"),
        gevent.spawn(coroutine_work, "work2")
])
  • 程序运行结果
work1 0
work2 0
work1 1
work1 2
work1 3
work2 1
work1 4
work2 2
work1 5
work2 3
work1 6
work1 7
work1 8
work2 4
work2 5
work1 9
work2 6
work2 7
work2 8
work2 9
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值