我正在使用python,我正在尝试使用生成器作为协同程序。这意味着我正在使用yield表达式将值传递给生成器,然后在各种生成器协同程序之间来回发送消息。
我正在尝试将协程链接到一个迭代一个值的循环中,同时保持对源自循环外部的新值的开放。换句话说,循环应该是非阻塞的:
这是循环:
coroutine_A -> val = (yield) -> does something to val -> coroutine_B.send(other_val)
coroutine_B -> val = (yield) -> does something to val -> coroutine_C.send(other_val)
coroutine_C -> val = (yield) -> does something to val -> coroutine_A.send(other_val)
有时候我想把这个循环外部的新值传递给coroutine_A,然后再将它关闭。
EXTERNAL TO LOOP -> coroutine_A.send(message) -> loop continues from new value...
单个部分工作正常,但当我尝试连接它们时会出现两个问题。首先,如何将这些实例化为循环,这似乎是可行的,但会导致更深层次的问题,如下所述。
第一个问题:
当实例化coroutine_A时,coroutine_B还不存在,所以还不能告诉coroutine_A它的消息目标是什么。基本上是一个鸡肉和鸡蛋的场景。
我已经尝试创建一个容器函数来实例化这些协同程序(没有消息目标),然后创建一个代表协同程序管理消息的循环,如下所示:
def func():
A = coroutine_A()
next(A)
B = coroutine_B()
next(B)
C = coroutine_C()
next(C)
message_A = A.send(None)
while True:
message_B = B.send(message_A)
message_C = C.send(message_B)
message_A = A.send(message_C)
这样做的问题是,它似乎不可能从循环外部传递消息,因为while循环只是卡在其中。
另一种解决方法是使用嵌套的yield表达式实例化coroutine_A,以便在实例化时间之后传入目标:
def coroutine_A():
while True:
val = (yield)
if val is not None:
coroutine_B_target = val
while True:
val = (yield)
if val is not None:
do something to val
coroutine_B_target.send(other_val)
A = coroutine_A()
next(A) # prime coroutine
A.send(B) # send in coroutine_B target and step into inner while loop
然而,当coroutine_C尝试向coroutine_A发送消息时,我得到一个ValueError异常:“生成器已经执行”。
所以这两种策略基本上都会导致:
更深层次的问题:
似乎作为协同程序的生成器无法自行循环,似乎这样做的原因是发送调用是一种“常规方法”,因此有效地尝试将调用堆栈链接回自身,即不允许每个David Beazley的Generators: The Final Frontier页127到131进行递归/重新进入。
因此有必要将信息传递给队列系统,然后出列并开始新的呼叫。但是当我尝试这个时,我似乎陷入了阻止来自循环外部的消息的While循环。
所以,长话短说,一方面,如何让循环保持循环,另一方面,如何保持对来自循环外部的新消息保持开放状态? < / p>