找了好些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()
效果: