生成器和协程 —你想知道的都在这里|老男孩IT教育(二)

    /    2019-05-21

yield from关键字

yield from关键字可以直接返回一个生成器

l = ['h','e','l']
dic = {'l':'v1','o':'v2'}
s = 'eva'
def yield_from_gen():
    for i in l:
        yield i
    for j in dic:
        yield j
    for k in s:
        yield k
for item in yield_from_gen():
    print(item,end='')
>>>helloeva
l = ['h','e','l']
dic = {'l':'v1','o':'v2'}
s = 'eva'
def yield_from_gen():
    yield from l
    yield from dic
    yield from s
for item in yield_from_gen():
    print(item,end='')
>>>helloeva

from itertools import chain
l = ['h','e','l']
dic = {'l':'v1','o':'v2'}
s = 'eva'
def yield_from_gen():
    yield from chain(l,dic,s)
for item in yield_from_gen():
    print(item,end='')
chain和yield from

利用yield from完成股票的计算,yield from能够完成一个委派生成器的作用,在子生成器和调用者之间建立起一个双向通道。

def son_gen():
    avg_num = 0
    sum_num = 0
    count = 1
    while True:
        num = yield avg_num
        if num:
            sum_num += num
            avg_num = sum_num/count
            count += 1
        else:break
    return avg_num
def depute_gen(key):
    while True:
        ret = yield from son_gen()
        print(key,ret)
def main():
    shares_list= {
        'sogou':[6.4,6.5,6.6,6.2,6.1,6.6,6.7],
        'alibaba':[181.72,184.58,183.54,180,88,169.88,178.21,189.32],
        '美团':[59.7,52.6,47.2,55.4,60.7,66.1,74.0]
    }
    for key in shares_list:
        g = depute_gen(key)
        next(g)
        for v in shares_list[key]:
            g.send(v)
        g.send(None)
main()


协程

根据维基百科给出的定义,“协程 是为非抢占式多任务产生子程序的计算机程序组件,协程允许不同入口点在不同位置暂停或开始执行程序”。从技术的角度来说,“协程就是你可以暂停执行的函数”。如果你把它理解成“就像生成器一样”,那么你就想对了。

使用yield实现协程

#基于yield实现异步
import time
def consumer():
    '''任务1:接收数据,处理数据'''
    while True:
        x=yield
def producer():
    '''任务2:生产数据'''
    g=consumer()
    next(g)
    for i in range(10000000):
        g.send(i)
producer()

使用yield from实现的协程

import datetime
import heapq    # 堆模块
import types
import time
class Task:
    def __init__(self, wait_until, coro):
        self.coro = coro
        self.waiting_until = wait_until
    def __eq__(self, other):
        return self.waiting_until == other.waiting_until
    def __lt__(self, other):
        return self.waiting_until < other.waiting_until
class SleepingLoop:
    def __init__(self, *coros):
        self._new = coros
        self._waiting = []
    def run_until_complete(self):
        for coro in self._new:
            wait_for = coro.send(None)
            heapq.heappush(self._waiting, Task(wait_for, coro))
        while self._waiting:
            now = datetime.datetime.now()
            task = heapq.heappop(self._waiting)
            if now < task.waiting_until:
                delta = task.waiting_until - now
                time.sleep(delta.total_seconds())
                now = datetime.datetime.now()
            try:
                print('*'*50)
                wait_until = task.coro.send(now)
                print('-'*50)
                heapq.heappush(self._waiting, Task(wait_until, task.coro))
            except StopIteration:
                pass
def sleep(seconds):
    now = datetime.datetime.now()
    wait_until = now + datetime.timedelta(seconds=seconds)
    print('before yield wait_until')
    actual = yield wait_until   # 返回一个datetime数据类型的时间
    print('after yield wait_until')
    return actual - now
def countdown(label, length, *, delay=0):
    print(label, 'waiting', delay, 'seconds before starting countdown')
    delta = yield from sleep(delay)
    print(label, 'starting after waiting', delta)
    while length:
        print(label, 'T-minus', length)
        waited = yield from sleep(1)
        length -= 1
    print(label, 'lift-off!')
def main():
    loop = SleepingLoop(countdown('A'5), countdown('B'3, delay=2),
                        countdown('C'4, delay=1))
    start = datetime.datetime.now()
    loop.run_until_complete()
    print('Total elapsed time is', datetime.datetime.now() - start)
if __name__ == '__main__':
    main()

(0)

分享至