如何使用python生成器创建非阻塞循环协程?

如何使用python生成器创建非阻塞循环协程?,python,loops,generator,yield,coroutine,Python,Loops,Generator,Yield,Coroutine,我正在使用python,并且正在尝试使用生成器作为协同程序。这意味着我正在使用yield表达式将值传递到生成器中,然后在这些生成器协程之间来回发送消息 我试图将协程链接到一个循环中,该循环迭代一个值,同时对来自循环外部的新值保持开放。换句话说,循环应该是非阻塞的: 这是一个循环: coroutine_A -> val = (yield) -> does something to val -> coroutine_B.send(other_val) coroutine_B -&g

我正在使用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)
我不时地想把一个新的值从这个循环的外部传递给协程,然后关闭它

EXTERNAL TO LOOP -> coroutine_A.send(message) -> loop continues from new value...
各个部分都很好,但当我试图将它们连接起来时,会出现两个问题。首先,如何将它们实例化为一个循环,这似乎是可行的,但会导致下面详述的更深层次的问题

第一期:

在实例化协程_A时,协程_B还不存在,因此还不能告诉协程_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循环只是在执行它的任务时被卡住了

另一种解决方法是使用嵌套的屈服表达式实例化协程_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
然而,当协程_C尝试向协程_a发送消息时,我得到一个ValueError异常:“生成器已在执行”

因此,这两种策略基本上都会导致:

更深层次的问题:

似乎作为协程的生成器不能在自身上循环,这似乎是因为发送调用是一种“普通方法”,因此有效地尝试将调用堆栈链回自身,即不允许按照David Beazley的第127至131页进行递归/重入

因此,有必要将信息传递给队列系统,然后退出队列并开始新的呼叫。但当我尝试这个方法时,我似乎被While循环卡住了,While循环阻止了来自循环外部的消息


那么,长话短说,一方面,一个人如何保持循环自身运转,另一方面,如何保持对来自循环外部的新消息的开放性呢?

也许,看一看,

也许这很接近:。@hustmphrr我来看看龙卷风的内部,尽管我的理解是Tornado一次只能处理一条消息,即使对该消息所做的操作可以异步处理?
Tornado
是单线程、非阻塞、异步、事件驱动的(副作用:不需要考虑线程安全)。所有代码都是以非阻塞方式编写的。是的,一次一条信息。然而,它更多地与吉尔有关。由于cpython的病态线程模型,很难用并发工作流实现真正的异步,唯一的方法是使用线程池(将由GIL序列化)和子进程同步信号(并发但沉重)。