python 协程 深入浅出(二)

为了更好理解python 里的协程机制,仿照asyncio的思路,写一个完全基于yield语法的的协程实现。对协程还有困惑的人,看了应该会有帮助。

下面代码基本实现了python3.5+ 协程的功能。

没有实现的功能包括:

协程的嵌套调用时,内部协程sleep信号如何传到外部协程,也就是await语法和协程标志。

python3.6+ 对协程都添加了标志,并通过await语法,让子协程的sleep操作可以传到外部,从而可以被事件循环捕获。因为这个处理比较复杂(虽然原理很简单),我就没有实现。

也因为我没有协程标志,所以我的Task类需要用isinstance来判断面对的是一个生成器还是一个普通函数。

import types
import traceback
import time

class Sleep():
    def __init__(self, n):
        assert isinstance(n, int)
        self.end = now()+n

now=lambda:time.time()
    
def every(func, a_list):
    ret = True
    for i in a_list:
        ret = ret and func(i)
    return ret
    
            
class Task(object):
    generator = type((i for i in range(1)))
    def __init__(self, corotine, *args):
        assert isinstance(corotine, self.generator) or isinstance(corotine, types.FunctionType)
        self.status = "pending"
        self.corotine = corotine
        self.args = args
    def start(self):
        try:
            self.status = "running"
            #print(self.status)
            try:
                while True:
                    tmp_status = next(self.corotine)
                    if isinstance(tmp_status, Sleep):
                        self.status = "sleep"
                        self.end_sleep = tmp_status.end
                        break
            except TypeError:
                result = self.corotine(*self.args)
                raise StopIteration(result)
        except StopIteration as result:
            self.status = "completed"
            self._result = result
        except:
            traceback.print_exc()
    @staticmethod
    def wait(task_list):
        def all_task():
            while True:
                for task in task_list:
                    #print(task.status)
                    if task.status == "sleep":
                        if now()>task.end_sleep:
                            task.status = "awake"
                            del(task.end_sleep)
                for task in task_list:
                    if task.status in ["pending", "awake"]:
                        #print(task.status)
                        task.start()
                if every(lambda i:i.status=="completed", task_list):
                    return task_list
        return Task(all_task)
    @staticmethod
    def sleep(n):
        return Sleep(n)
    def result(self):
        assert self.status == "completed"
        return self._result
class Loop(object):
    def __init__(self):
        pass
    def run_until_complete(self, task, *args):
        if not isinstance(task, Task):
            task = Task(task, *args)
        assert isinstance(task, Task)
        Task.wait([task]).start()
        
def a():
    print("a: ","hello")
    for _ in range(5):
        yield Task.sleep(1)
        print("a: ", "bye")
    return "goodbye"
def b():
    print("b: haha")
    for _ in range(5):
        yield Task.sleep(1)
        print("b: again")
    return "nihao"
def c():
    for i in range(10):
        print("c:",i)
    return "nice"
loop = Loop()
task1 = Task(a())
task2 = Task(b())
task3 = Task(c)
task = Task.wait([task1, task2, task3])
loop.run_until_complete(task)
print(task.result())
print(task1.result())
print(task2.result())
print(task3.result())
        

        
        
        

猜你喜欢

转载自my.oschina.net/backbye/blog/1825926
今日推荐