python协程是个不错的东东,如果计算拓扑中有环的话可以通过消息缓冲实现。
from collections import deque
class delegate:
'''协程函数代理,有代理后协程间的关系允许有环'''
def __init__(self,func):
'''初始化,func为协程函数,将创建消息缓冲队列'''
self.msgbuf = deque()
self.func = func
def __call__(self,*args,**kwargs):
'''启动协程'''
self.funcgen = self.func(*args,**kwargs)
return self.funcgen
def send(self,msg):
'''对协程send消息的代理函数'''
try:
#先发送队列中的消息,之后发送新消息
while len(self.msgbuf) > 0:
self.funcgen.send(self.msgbuf[0])
self.msgbuf.popleft()
self.funcgen.send(msg)
except ValueError:
#发送失败则将新消息加入队列
self.msgbuf.append(msg)
except StopIteration:
self.stop()
def stop(self):
'''最后需将队列中的消息发出'''
while len(self.msgbuf) > 0:
self.funcgen.send(self.msgbuf[0])
self.msgbuf.popleft()
def coroutine(func):
'''协程的修饰函数,修饰后不需调用next'''
def newfunc(*args,**argss):
generator = func(*args,**argss)
generator.next()
return generator
return newfunc
#例子 a -> b -> c-> b,消息在b、c间来回转发
def ag(outstream):
for i in range(3):
outstream.send( ("a",i) )
@coroutine
def bg(outstream):
while True:
src, msg = (yield)
print "b received:",src,msg
if src != "c":
outstream.send( ("b",(src,msg)) )
@coroutine
def cg(outstream):
while True:
src, msg = (yield)
print "c received:",src,msg
outstream.send( ("c",(src,msg)) )
bd=delegate(bg) #创建b的代理对象
c=cg(bd) #用b的代理对象初始化c
b=bd(c) #有c后初始化b
a=ag(bd) #用b的代理初始化a,a启动发布数据
bd.stop() #通知b的代理结束,缓冲区的数据继续发完
结果:
b received: a 0
c received: b ('a', 0)
b received: c ('b', ('a', 0))
b received: a 1
c received: b ('a', 1)
b received: c ('b', ('a', 1))
b received: a 2
c received: b ('a', 2)
b received: c ('b', ('a', 2))