python generator和coroutine入门

2018-09-03  本文已影响0人  慢手暗夜

生成器(generator)

一般的函数return后,函数栈被销毁,下次调用的时候从新开始。生成器函数可以yield一个值,暂停执行,把执行权交给调用函数,当我们获取另一个值得时候,生成器函数可以恢复执行。

调用生成器函数的时候,我们得到的是一个生成器对象(类似迭代器)。当我们在生成器对象上调用next()便会得到yield返回的值。下面是两个例子,一个是通过next()获取yield值,另一个是通过循环。

code sample:

def generator_sample():
    yield "Hello"
    yield "World"


generator_obj = generator_sample()
print(generator_obj)
print(next(generator_obj))
print(next(generator_obj))

result:

<generator object generator_sample at 0x00D910B0>
Hello
World
def generator_sample():
    yield "Hello"
    yield "World"


generator_obj = generator_sample()
print(generator_obj)
for i in generator_obj:
    print(i)

result:

<generator object generator_sample at 0x005A10B0>
Hello
World

生成器函数的用处:通过迭代而不是一次性获取所有值,避免消耗大内存。可以利用生成器函数返回多个值。

基于生成器的协程

通过生成器,我们可以从函数中获取值。那么如何给生成器函数发送值呢?这就是协程的作用。我们可以通过generator对象的send()函数给生成器函数返回一个值。如下示例:

def coroutine_base_on_generator():
    temp = yield "yes"
    yield temp


c_obj = coroutine_base_on_generator()
print(next(c_obj))
print(c_obj.send("you are right"))

result:

yes
you are right

asyncio module

从python3.4,引入了asyncio模块,提供了优雅的异步编程接口。但是依然是基于生成器的协程。下面是asyncio module的示例:

import asyncio
import datetime
import random


@asyncio.coroutine
def asyncio_module_sample(num, count):
    i = 0
    while i < count:
        print("Loop: {} Time: {}".format(num, i))
        yield from asyncio.sleep(random.randint(0, 5))
        i += 1


loop = asyncio.get_event_loop()
task1 = loop.create_task(asyncio_module_sample(1, 5))
task2 = loop.create_task(asyncio_module_sample(2, 5))
try:
    loop.run_until_complete(asyncio.wait([task1, task2]))
finally:
    loop.close()

result:

Loop: 1 Time: 0
Loop: 2 Time: 0
Loop: 2 Time: 1
Loop: 1 Time: 1
Loop: 2 Time: 2
Loop: 1 Time: 2
Loop: 2 Time: 3
Loop: 2 Time: 4
Loop: 1 Time: 3
Loop: 1 Time: 4

async/await

从python3.5,引入了async/await语法关键字。所以之前的例子可以用async/await方式重写:

import asyncio
import datetime
import random


async def async_await_sample(num, count):
    i = 0
    while i < count:
        print("Loop: {} Time: {}".format(num, i))
        await asyncio.sleep(random.randint(0, 5))
        i += 1


loop = asyncio.get_event_loop()

try:
    loop.run_until_complete(asyncio.gather(async_await_sample(1, 5), async_await_sample(2, 5)))
finally:
    loop.close()

result:

Loop: 1 Time: 0
Loop: 2 Time: 0
Loop: 1 Time: 1
Loop: 2 Time: 1
Loop: 1 Time: 2
Loop: 1 Time: 3
Loop: 2 Time: 2
Loop: 1 Time: 4
Loop: 2 Time: 3
Loop: 2 Time: 4

async/await方式和asyncio module方式在功能上并没有区别,只是语法的差异。但是两者不能混用。

上一篇下一篇

猜你喜欢

热点阅读