search

Home  >  Q&A  >  body text

Python 协程的无限递归的问题

hi, 最近看了关于Python协程的相关文章协程的简单理解,说协程可以无限递归,于是想写一个协程示例练练,于是:

import time


def ping():
    print 'ping 0'
    count = 1
    try:
        pi,po = yield s
        print 'ping ' + str(count)
        count += 1     
        time.sleep(1)
        po.send([po, pi])
    except StopIteration:
        pass


def pong():
    print 'pong 0'
    count = 1
    try:
        po, pi = yield s
        print 'pong ' + str(count)
        count += 1
        time.sleep(1)
        pi.send([pi,po])
    except StopIteration:
        pass


s = ping()
r = pong()
s.next()
r.next()
s.send([s,r])

运行结果是:

ping 0
pong 0
ping 1
pong 1
Traceback (most recent call last):
  File "D:\test\coroutine.py", line 34, in <module>
    s.send([s,r])
  File "D:\test\coroutine.py", line 12, in ping
    po.send([po, pi])
  File "D:\test\coroutine.py", line 25, in pong
    pi.send([pi,po])
ValueError: generator already executing

那篇文章使用了stackless,我想实现一个原始的方法。但是出错,不知道要实现无限递归的话,应该怎么写嘞?

PHP中文网PHP中文网2770 days ago837

reply all(4)I'll reply

  • 天蓬老师

    天蓬老师2017-04-17 15:46:45

    What you need is to use a run function to manage the coroutine.
    In the ping and pong functions, yield returns run.
    In the run function, use next() to schedule the coroutine.

    import time
    
    def ping():
        print 'ping 0'
        count = 1
        while 1:
            yield po
            print 'ping ' + str(count)
            count += 1
            time.sleep(1)
    
    def pong():
        print 'pong 0'
        count = 1
        while 1:
            yield pi
            print 'pong ' + str(count)
            count += 1
            time.sleep(1)
    
    def run(co):
        while 1:
            co = co.next() # 这行实现 ping 和 pong 交替运行
    
    pi = ping()
    po = pong()
    pi.next()
    po.next()
    run(pi)

    Run result:

    ping 0
    pong 0
    ping 1
    pong 1
    ping 2
    pong 2
    ping 3
    pong 3
    ping 4
    pong 4
    ......

    ==================================================== =======
    With messaging version:

    import time
    
    def ping():
        print 'ping 0'
        count = 1
        while 1:
            msg = yield (po, 'msg from ping')
            print 'ping get', msg
            print 'ping ' + str(count)
            count += 1
            time.sleep(1)
    
    def pong():
        print 'pong 0'
        count = 1
        while 1:
            msg = yield (pi, 'msg from pong')
            print 'pong get', msg
            print 'pong ' + str(count)
            count += 1
            time.sleep(1)
    
    def run(cur, msg='msg from run'):
        while 1:
            cur, msg = cur.send(msg)
    
    pi = ping()
    po = pong()
    pi.next()
    po.next()
    run(pi)

    Run result:

    ping 0
    pong 0
    ping get msg from run
    ping 1
    pong get msg from ping
    pong 1
    ping get msg from pong
    ping 2
    pong get msg from ping
    pong 2
    getping msg from pong
    ping 3
    pong get msg from ping
    pong 3
    ping get msg from pong
    ping 4
    ............

    reply
    0
  • PHP中文网

    PHP中文网2017-04-17 15:46:45

    There is indeed a problem with what you wrote, but the most important thing is that Stackless is a modified version of Python. Its coroutines seem to be different from those in standard CPython. If you want to implement similar functions in CPython, you may need to Based on greenlet.

    reply
    0
  • 高洛峰

    高洛峰2017-04-17 15:46:45

    http://anandology.com/blog/using-iterators-and-generators/
    It should be that the problem is caused by passing the generator itself, and it is caused by send itself
    If pi po is a global variable, there should be no problem

    reply
    0
  • 迷茫

    迷茫2017-04-17 15:46:45

    The usage of the generator is obviously wrong. s is not suspended by yield. Of course, if you go to send/next again, this error will be reported
    I don’t know what you want to achieve specifically. If you want to print “ping pong” alternately, just use a generator

    reply
    0
  • Cancelreply