Python高级编程技巧---协程

先来说几个概念
同步: 代码调用IO操作时,必须等到操作完成返回的调用方式,同步是并行
异步: 代码调用IO操作时,必须等到操作完成返回的调用方式,异步是串行
阻塞: 从调用者的角度说,如果调用时被卡住,不再往下执行,需要等待就是说阻塞
非阻塞: 从调用者的角度说,如果调用时没有被卡住,继续往下执行无需等待就是说非阻塞

生成器—send方法
  1. 启动生成器
  2. 发送值给生成器返回
def generator(num):
    a, b = 0, 1
    con = 0
    while con < num:
        result = yield a  # 先执行右边,会阻塞在这里
        print('result>>', result)
        a, b = b, a + b
        con += 1
    return 123


g = generator(5)
g.close()  # 关闭生成器,后续的值将取不了
# send 方法可以启动生成器都是第一次传的值必须是空
print(next(g))   # 这也可以取出来
print(g.send('huran'))

for i in g:   # 还可以用for循环
    print(i, end='-')
# 捕获生成器的返回值
while True:
    try:
        ret = next(g)
        print(ret)
    except Exception as e:
        print(e.value)
        break

在这里插入图片描述

yield完成多任务

利用就是yield会阻塞的特性

import time

def task1():
    while True:
        print("--1--")
        time.sleep(0.1)
        yield

def task2():
    while True:
        print("--2--")
        time.sleep(0.1)
        yield

def main():
    t1 = task1()
    t2 = task2()
    while True:
        next(t1)
        next(t2)

if __name__ == "__main__":
    main()
yield from

chain()可传入多个可迭代的对象,对他们进行一个for循环取出值来。

lis = [1, 2, 3]
dis = {
    'name': 'juran',
    'age': 18
}


def my_chian(*args, **kwargs):
    for val in args:
        yield from val


for value in my_chian(lis, dis):
    print(value)

yield from

def generator_1():   # 子生成器
    total = 0
    while True:
        x = yield
        print('加', x)
        if not x:   
            break
        total += x
    return total


def generator_2():  # 委托生成器
    while True:
        total = yield from generator_1()  # 子生成器
        print('加和总数是:', total)


def main():  # 调用方
    # g1 = generator_1()
    # g1.send(None)
    # g1.send(2)
    # g1.send(3)
    # g1.send(None)
    g2 = generator_2()
    g2.send(None)
    g2.send(2)
    g2.send(3)
    g2.send(None)


if __name__ == '__main__':
    main()

【子生成器】:yield from后的generator_1()生成器函数是子生成器
【委托生成器】:generator_2()是程序中的委托生成器,它负责委托子生成器完成具体任务。
【调用方】:main()是程序中的调用方,负责调用委托生成器。

协程

协程,又称微线程
协程是python个中另外一种实现多任务的方式,只不过比线程更小占用更小执行单元(理解为需要的资源)
Python中的协程大概经历了如下三个阶段:

  1. 最初的生成器变形yield/send
  2. yield from
  3. 在最近的Python3.5版本中引入async/await关键字

协程的实现



from greenlet import greenlet
import time


def greenlet_1():
    while True:
        print('--1--')
        g2.switch()
        time.sleep(0.5)


def greenlet_2():
    while True:
        print('--2--')
        g1.switch()
        time.sleep(0.5)


g1 = greenlet(greenlet_1)
g2 = greenlet(greenlet_2)
g1.switch()

gevent实现多任务
遇到等待会自动切换到另外一个任务

import gevent
from gevent import monkey  
monkey.patch_all()  # 将所用的噩耗时操作换为gevent模块的


def test1(n):
    for i in range(n):
        print(gevent.getcurrent(), i)
        gevent.sleep(0.5)  # 这里会有等待,会自动在上一步自动切换到另外一个


def test2():
    while True:
        print(gevent.getcurrent(), '---2---')
        gevent.sleep(0.5)  # 这里会有等待,会自动在上一步自动切换到另外一个


t1 = gevent.spawn(test1, 2)  # 第一个参数是对象,第二个是参数(传入函数中的,可有可无)
t2 = gevent.spawn(test2)
t1.join()  # 要等到执行完毕,否则直接到这里
t2.join()

案例:

import gevent
from gevent import monkey
monkey.patch_all()
import requests


def download(url):
    print("get:%s" % url)
    ret = requests.get(url)
    data = ret.text
    print(len(data), ret)


g1 = gevent.spawn(download, 'https://www.kancloud.cn/ju7ran/gaoji/1474878')
g2 = gevent.spawn(download, 'https://fanyi.baidu.com/?fr=websearch_submit&pid=sogou__free#pt/zh/%3CGreenlet')
g1.join()
g2.join()
访问的网站并不是按照你写的顺序来执行完成的,而是先执行完时间短一点的,

总结:
进程是资源分配的基本单位
线程是操作系统调度和执行的单位
进程切换需要的资源很最大,效率很低
线程切换需要的资源一般,效率一般(当然了在不考虑GIL的情况下)
协程切换任务资源很小,效率高
多进程、多线程根据cpu核数不一样可能是并行的,但是协程是在一个线程中 所以是并发

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值