python协程

协程

协程概念:

协程: 又称微线程,纤程,协程是一种用户态的轻量级线程。

协程的作用: 在执行A函数的时候,可以随时中断,去执行B函数,然后中断继续执行A函数(可以自动切换),协程过程并不是函数调用(没有调用语句),过程很像多线程,然而协程只有一个线程在执行。

特点:

  • 必须在只有一个单线程中实现并发
  • 用户可以在自己的程序中保存多个控制流的的上下文栈
  • 修改共享数据并不需要加锁
  • 一个协程在遇到IO操作时自动切换到其他协程中
  • 线程是CPU控制的,而协程是程序自身控制的。

协程原理:

​ 协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。因此:协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置。

**优点 **

  • 无需原子操作的锁定和开销
  • 方便切换控制流,简化编程模型
  • 方便实现并发任务,可扩展性强,成本低

缺点:

  • 无法利用多核资源:

    协程的本质是个单线程,它不能同时将使用单个CPU 的多个核,协程需要和进程配合才能运行在多CPU上。

  • 当进行阻塞操作时,会阻塞整个程序。

协程的实现:

1、yield、send

​ 方案1协程通过yield和send来进行实现,具体实例:

def A():
    print("start")
    value = 0
    while True:
        receive = yield value
        if receive == "quit":
            break
        print("A:::get a num is ::%d" % receive)
        value = receive * 10


def B():
    g = A()
    g.send(None)  # 启动
    l = [i for i in range(3)]
    len_l = len(l)
    i = 0
    while len_l > 0:
        value = g.send(l[i])
        print("B:::get a num %d" % value)
        len_l -= 1
        i += 1
    try:
        g.send("quit")
    except:
        print("结束协程,end")


B()
################################################################################
"""结果展示:"""
#start
#A:::get a num is ::0
#B:::get a num 0
#A:::get a num is ::1
#B:::get a num 10
#A:::get a num is ::2
#B:::get a num 20
#结束协程,end

在上述实例中,A()receive = yield value 语句执行顺序主要是:

  • 1、向函数外部抛出value
  • 2、暂停执行,等待next()或者send()函数唤醒
  • 3、被send()唤醒后,将send()发送数据赋值给receive

在启动时,先以send(None)启动生成器函数,如果以其他值启动会报错,之后执行的顺序实际为”3-1-2“循环执行,实例中B先向send()一条数据,A接受到数据后进行乘10处理,之后将结果返回给B,暂停等待B再次唤醒。

2、yield from

t = range(3)
def f1():
    yield t

def f2():
    yield from t


f1=f1()
f2=f2()
for _ in f1:
    print("f1::",_)
for _ in f2:
    print("f2::",_)
#########################
"""结果"""
#f1:: range(0, 3)
#f2:: 0
#f2:: 1
#f2:: 2

这里的yield from相当于实现了一次for循环,yield from之后必须接的是生成器或者迭代器,同时yield from也可以打开双通道实现协程操作

现在使用yield from代替for循环,yield from后面必须跟iterable对象(可以是生成器,迭代器)

3、asyncio.coroutine和yield from

@asyncio.coroutine 与 yield from结合实现协程

我们先看一下没用使用协程的运行状况:

def task1(n):
    print("task1开始工作")
    time.sleep(n)
    print("task1工作结束")
def task2(n):
    print("task2开始工作")
    time.sleep(n)
    print("task2工作结束")

start=time.time()
task1(2)
task2(4)
end=time.time()
print("任务总需要的时间:",end-start)
############################################
"""实验结果:"""
#task1开始工作
#task1工作结束
#task2开始工作
#task2工作结束
#任务总需要的时间: 6.002887725830078

当使用@asyncio.coroutine与yield from时

@asyncio.coroutine  # 标志协程的装饰器
def task1_asyn(n):
    print("task1开始工作")
    yield from asyncio.sleep(n)  # 这里一般为需要耗费大量时间的操作
    print("task1工作结束")
@asyncio.coroutine
def task2_asyn(n):
    print("task2开始工作")
    yield from asyncio.sleep(n)
    print("task2工作结束")

start=time.time()
loop=asyncio.get_event_loop()  # 获取一个循环对象loop
tasks=[task1_asyn(2), task2_asyn(4)]
loop.run_until_complete(asyncio.wait(tasks))  # 完成事件循环,直到最后一个任务结束
loop.close()
end=time.time()
print("任务总需要的时间:",end-start)
###########################################
#task2开始工作
#task1开始工作
#task1工作结束
#task2工作结束
#任务总需要的时间: 4.004240274429321

我们可以明显看到整个任务所需要的时间比之前少了好多

4、async和await

他们可以理解成asyncio.coroutine/yield from的完美实现。当然,从Python设计的角度来说,async/await让协程表面上独立于生成器而存在,将细节都隐藏于asyncio模块之下,语法更清晰明了。加入新的关键字 async ,可以将任何一个普通函数变成协程。

async def mygen(alist):
    while len(alist)>0:
        index = random.randint(0, len(alist)-1)
        print(alist.pop(index))
alist=['java', 'python', 'C++', 'C']
print(mygen(alist))
###################################
"""结果"""
#<coroutine object mygen at 0x000001E1CF3E4A48>

配合await实现协程

async def mygen(alist):
    while len(alist)>0:
        index = random.randint(0, len(alist)-1)
        print(alist.pop(index))
        await asyncio.sleep(0.2)
t1=['java', 'python', 'C++', 'C']
t2=[1,2,3,4,5,6,7,8]
tasks=[mygen(t1),mygen(t2)]
loop=asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
###################################################
"""测试结果:"""
#3
#java
#5
#python
#4
#C
#7
#C++
#2
#8
#1
#6

我们可以看到,这里没有调用多线程,但是协程实现了两个任务的交替进行,实现异步非阻塞方式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值