Python协程,使用yield手写协程实现

找了好些Python的协程资料,也找到了好多别人实现的协程,但用着不顺手所以决定自己手动写。

借鉴于C#的协程实现来写,包括协程实现类和控制类,目前需要按时间控制和按帧数控制,所以控制类只写了这两种大多情况下也只会用到这两种

实现:

import datetime
from time import sleep
# 协程控制接口


class ICoroutineWait:
    def Wait(self):
        return False
# 按时间等待


class WaitForTime(ICoroutineWait):
    def __init__(self, time)-> None:
        super().__init__()
        if(type(time) == datetime.datetime):
            self.time = time
        else:
            self.time = datetime.datetime.now() + datetime.timedelta(seconds=time)
        self.finish = False

    def Wait(self):
        return self.time.__gt__(datetime.datetime.now())

# 按帧数等待

class WaitForFrame(ICoroutineWait):
    def __init__(self, frame)->None:
        super().__init__()
        self.frame = frame

    def Wait(self):
        self.frame -= 1
        return self.frame >= 0

# 协程类


class Coroutine:
    def __init__(self, iter, time):
        self._iter = iter
        self.finish = False
        self.name = None
        self._wait = WaitForTime(time)

    def Update(self):
        if not self._wait:
            return
        if self.finish or self._wait.Wait():
            return
        try:
            self._wait = next(self._iter)
        except StopIteration:
            self.finish = True

    def Relese(self):
        self.name = None
        self._wait = None
        if self._iter:
            self._iter.close()
        self._iter = None


# 协程对象基类


class CoroutineObject:
    Tick = datetime.timedelta(milliseconds=17)
    __nextTime = datetime.datetime.now()
    __Objects = []

    def __init__(self):
        self.__Objects.append(self)  # 收集子对象
        self.__Coroutines = []
    # 释放资源

    def Relese(self):
        CoroutineObject.__Objects.remove(self)
        for cor in self.__Coroutines:
            cor.Relese()
        self.__Coroutines.clear()
    # 独立更新,从总更新列表中移除

    def Distinct(self):
        CoroutineObject.__Objects.remove(self)
    # 更新全部子对象

    def UpdateObjects():
        time = datetime.datetime.now()
        if(CoroutineObject.__nextTime>time):
            return
        CoroutineObject.__nextTime = time + CoroutineObject.Tick
        
        for ob in CoroutineObject.__Objects:
            ob.UpdateCoroutines()
    # 更新全部协程

    def UpdateCoroutines(self):
        finishlist = []
        for cor in self.__Coroutines:
            cor.Update()
            if(cor.finish):
                finishlist.append(cor)
        for fcor in finishlist:
            self.__Coroutines.remove(fcor)
            fcor.Relese()
    # 启动一个协程

    def StartCoroutine(self, iter, waitSeconds=0):
        coroutine = Coroutine(iter, waitSeconds)
        self.__Coroutines.append(coroutine)
        return coroutine
    # 添加一个手动创建的协程

    def AddCoroutine(self, coroutine):
        self.__Coroutines.append(coroutine)

    # 结束第一个匹配名字的协程,必须事先命名
    def StopCoroutine(self, name):
        if len(name) <= 0:
            return
        for cor in self.__Coroutines:
            if cor.name == name:
                self.__Coroutines.remove(cor)
                cor.Relese()
                return
    # 结束所有协程

    def StopAllCoroutine(self):
        for cor in self.__Coroutines:
            cor.Relese()
        self.__Coroutines.clear()

使用:

class Test(CoroutineObject):
    def Start(self):
        print("Test:创建协程,立马执行")
        self.StartCoroutine(self.func())

    def func(self):
        print("Test:开始执行协程")
        print("Test:等待5秒。。。")
        yield WaitForTime(5)
        print("Test:5秒时间到,再等待100帧后结束。。。")
        yield WaitForFrame(100)
        print("Test:协程结束。。。")
        self.end = True

class Test1(CoroutineObject):
    def BeginShowTime(self):
        print("Test1:开始循环输出当前时间")
        self.StartCoroutine(self.LoopShowTime())
        
    def LoopShowTime(self):
        #循环每秒输出当前时间
        while True:
            print("Test1:当前时间:",datetime.datetime.now())
            yield WaitForTime(1)

def main():
    t = Test()
    t.Start()

    t1 = Test1()
    t1.BeginShowTime()

    time2 = datetime.datetime.now()
    CoroutineObject.Tick = datetime.timedelta(
        milliseconds=17)  # 对于所有协程来说最小的时间单位将是17毫秒 大概60帧/s
    while True:  # 主循环
        time3 = datetime.datetime.now()
        CoroutineObject.UpdateObjects()#协程总更新
        if time2 > time3:
            sleep(0.001)  # sleep 1毫秒
            continue
        print("主循环:处理主循环别的事情。。。")
        time2 = time3 + datetime.timedelta(seconds=1)

if __name__ == '__main__':
    main()

效果:

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值