Python--协程

生成器 g

生成器generator以及yield表达式详解

  • ret = yield expression
  • next(g)
  • g.send(arg)
  • g.throw(Exception)
  • g.close()
  • return msg
  • StopIteration msg
点击查看代码
def my_generator(n):
    for i in range(n):
        temp = yield i
        print(f'我是{temp}')


g = my_generator(5)

print(next(g))  # 输出0
print(next(g))  # 输出1
# g.send(100)  # 本来输出2,但是传入新的值100,改为输出100
print(g.send(100))
print(next(g))  # 输出3
print(next(g))  # 输出4

'''
0#第一次迭代
---------------------
我是None
1#第二次迭代
---------------------
我是100#第三次迭代
---------------------
我是None#第四次迭代
3
---------------------
我是None#第五次迭代
4
'''

print('-------------------------')


def my_generator2():
    try:
        yield 'a'
        yield 'b'
        yield 'c'
        yield 'd'
        yield 'e'
    except ValueError:
        print('触发“ValueError"了')
    except TypeError:
        print('触发“TypeError"了')


g = my_generator2()
print(next(g))
print(next(g))
print('-------------------------')
print(g.throw(ValueError))
print('-------------------------')
print(next(g))
print(next(g))
print('-------------------------')
print(g.throw(TypeError))
print('-------------------------')
print(next(g))

print('-------------------------')


def my_generator3():
    yield 1
    return 'return返回了'
    yield 2


g = my_generator3()
print(next(g))
print(next(g))
print(next(g))

生成器状态

使用yield关键字实现协程
Python协程详解(一)

  • GEN_CREATED:等待执行
  • GEN_RUNNING:解释器执行
  • GEN_SUSPENDED:在yield表达式处暂停
  • GEN_CLOSED:执行结束
点击查看代码
import datetime
from inspect import getgeneratorstate
from time import sleep
import threading


def get_state(coro):
    while True:
        print(datetime.datetime.now(), "其他线程生成器状态:%s", getgeneratorstate(coro))
        sleep(1)


def simple_coroutine():
    for i in range(3):
        print(datetime.datetime.now(), 'simple_coroutine', i+1)
        sleep(3)
        x = yield i + 1


my_coro = simple_coroutine()
print(datetime.datetime.now(), "生成器初始状态:%s" % getgeneratorstate(my_coro))
t = threading.Thread(target=get_state, args=(my_coro,))
t.setDaemon(True)
t.start()
first = next(my_coro)
print(datetime.datetime.now(), 'simple_coroutine返回:', first)
print(datetime.datetime.now(), '开始循环')
for i in range(5):
    try:
        print(datetime.datetime.now(), 'simple_coroutine返回:', my_coro.send(i))
        print(datetime.datetime.now(), "主线程生成器初始状态:%s" % getgeneratorstate(my_coro))

    except StopIteration:
        print(datetime.datetime.now(), "生成器的值拉取完毕")
print(datetime.datetime.now(), "生成器最后状态:%s" % getgeneratorstate(my_coro))

''' 输出结果:
2021-10-09 17:23:44.376290 生成器初始状态:GEN_CREATED
2021-10-09 17:23:44.378290 其他线程生成器状态:%s GEN_CREATED
2021-10-09 17:23:44.379277 simple_coroutine 1
2021-10-09 17:23:45.389752 其他线程生成器状态:%s GEN_RUNNING
2021-10-09 17:23:46.396555 其他线程生成器状态:%s GEN_RUNNING
2021-10-09 17:23:47.393188 simple_coroutine返回: 1
2021-10-09 17:23:47.393188 开始循环
2021-10-09 17:23:47.393188 simple_coroutine 2
2021-10-09 17:23:47.409192 其他线程生成器状态:%s GEN_RUNNING
2021-10-09 17:23:48.419401 其他线程生成器状态:%s GEN_RUNNING
2021-10-09 17:23:49.428855 其他线程生成器状态:%s GEN_RUNNING
2021-10-09 17:23:47.393188 simple_coroutine返回: 2
2021-10-09 17:23:50.406583 主线程生成器初始状态:GEN_SUSPENDED
2021-10-09 17:23:50.406583 simple_coroutine 3
2021-10-09 17:23:50.437131 其他线程生成器状态:%s GEN_RUNNING
2021-10-09 17:23:51.448273 其他线程生成器状态:%s GEN_RUNNING
2021-10-09 17:23:52.459059 其他线程生成器状态:%s GEN_RUNNING
2021-10-09 17:23:50.406583 simple_coroutine返回: 3
2021-10-09 17:23:53.408010 主线程生成器初始状态:GEN_SUSPENDED
2021-10-09 17:23:53.408010 生成器的值拉取完毕
2021-10-09 17:23:53.408010 生成器的值拉取完毕
2021-10-09 17:23:53.408010 生成器的值拉取完毕
2021-10-09 17:23:53.408010 生成器最后状态:GEN_CLOSED
'''

生成器实现协程

使用yield关键字实现协程

  • 根据send传入的值,生成器可以返回不同的结果
点击查看代码
def consumer():
    r = ''
    while True:
        n = yield r  # 执行的中断点
        if not n:
            return
        print('[消费者] 正在消费:{0}'.format(n))
        r = f'{n * 100} 人民币'  # 根据send进来的值返回不同的结果


def produce(c):
    c.send(None)  # 启动消费者(生成器)——实际上是函数调用,只不过生成器不是直接象函数那般调用的
    n = 0
    while n < 5:
        n = n + 1
        print('[生产者] 正在生产:{0}'.format(n))
        r = c.send(n)  # 给消费者传入值——实际上也是函数调用
        print('[生产者] 消费者返回:{0}'.format(r))
        print('-------------------------------------------------')
    c.close()


c = consumer()  # 构造一个生成器
produce(c)

'''运行结果为:
[生产者] 正在生产:1
[消费者] 正在消费:1
[生产者] 消费者返回:100 人民币
-------------------------------------------------
[生产者] 正在生产:2
[消费者] 正在消费:2
[生产者] 消费者返回:200 人民币
-------------------------------------------------
[生产者] 正在生产:3
[消费者] 正在消费:3
[生产者] 消费者返回:300 人民币
-------------------------------------------------
[生产者] 正在生产:4
[消费者] 正在消费:4
[生产者] 消费者返回:400 人民币
-------------------------------------------------
[生产者] 正在生产:5
[消费者] 正在消费:5
[生产者] 消费者返回:500 人民币
-------------------------------------------------
'''

yield from

yield from原理详解

点击查看代码
def my_generator():
    for i in range(5):
        if i == 3:
            return '我被迫中断了'
        else:
            yield i


def wrap_my_generator(generator):  # 定义一个包装“生成器”的生成器,它的本质还是生成器
    result = yield from generator  # 自动触发StopIteration异常,并且将return的返回值赋值给yield from表达式的结果,即result
    print('wrap_my_generator', result)


def main(generator):
    for j in generator:
        print('main', j)

# def main(generator):
#     print('main', next(generator))
#     print('main', next(generator))
#     # print('main', generator.throw(Exception('异常来了')))
#     # print('main', generator.throw(StopIteration('异常来了')))
#     print('main', next(generator))
#     print('main', next(generator))
#     print('main', next(generator))


g = my_generator()
wrap_g = wrap_my_generator(g)
main(wrap_g)  # 调用
'''运行结果为:
main 0
main 1
main 2
wrap_my_generator 我被迫中断了
'''

Asyncio

asyncio的核心概念与基本架构

  1. coroutine(协程)
    • yield/yield from (3.5之前)
    • async/await (3.5及之后)
  2. event loop(事件循环)
    • loop = asyncio.get_running_loop() (3.7版本加)
    • loop = asyncio.get_event_loop()
    • loop = asyncio.new_event_loop()
    • asyncio.set_event_loop(loop)
    • 一个线程只能有一个event loop
  3. awaitable对象
    • coroutine、Task、Future
    • coroutine本质是一个函数,可自动封装成为Task,Task是Future的子类
  4. 创建任务
    • loop.create_task(coro) 将协程转Task
    • loop.create_future() 创建Future (这里是不是就把任务添加到事件循环里面了呢??)
    • asyncio.create_task(coro) (3.7版本加)
    • asyncio.ensure_future(coro_or_future) 当参数是coro时,函数里面调用的就是loop.create_task(coro) 3.5+版本参数coro_or_future可以是一个awaitable对象
  5. 多任务
    • done,pending = await asyncio.wait([task1, task2,...])
    • results = await asyncio.gather(*[task1, task2,...])
  6. 运行事件循环
    • loop.run_until_complete(asyncio.wait([task1, task2,...]))
    • loop.run_until_complete(asyncio.gather(*[task1, task2,...]))
    • loop.run_until_complete(task)
    • loop.run_forever()
    • asyncio.run() (3.7版本加)

小例子

点击查看代码
import asyncio
import random
import sys
from datetime import datetime


# 3
async def consumer():
    while True:
        item = await queue.get()
        print(datetime.now(), "I'm working hard", item)
        await asyncio.sleep(random.random() * 3)


async def producer():
    while True:
        await queue.put(random.randint(0, sys.maxsize))
        print(datetime.now(), 'count:', queue.qsize())
        await asyncio.sleep(random.random() * 2)


# 2
# async def worker():
#     print(datetime.now(), "I'm working hard")
#
#
# async def main():
#     while True:
#         asyncio.ensure_future(worker())
#         await asyncio.sleep(random.random() * 2)

# 1
# def main():
#     asyncio.ensure_future(consumer())
#     asyncio.ensure_future(producer())


# 1 3
queue = asyncio.Queue()
# 1
# main()
loop = asyncio.get_event_loop()
# 1
# loop.run_forever()
# 2
# loop.run_until_complete(main())
# 3
loop.run_until_complete(asyncio.wait([consumer(), producer()]))

原文地址:https://www.cnblogs.com/yarightok/p/15387128.html