搜尋

首頁  >  問答  >  主體

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 天前843

全部回覆(4)我來回復

  • 天蓬老师

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

    你需要的是用一個 run 函數來管理協程。
    在 ping 和 pong 函數內,yield 傳回 run。
    在 run 函數內,以 next() 對協程進行調度。

    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)

    運行結果:

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

    pong 3
    ping 4

    pong 4
    .........

    ================================================= =======

    帶訊息傳遞版:

    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)
    運行結果:



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

    回覆
    0
  • PHP中文网

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

    你寫的確實是有問題,不過最主要的是,Stackless是一個修改版的Python,它的coroutine和標準CPython裡的貌似不太一樣,如果你想要在CPython裡面實現類似的功能,可能需要基於greenlet來做。

    回覆
    0
  • 高洛峰

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

    http://anandology.com/blog/using-iterators-and-generators/
    應該是把generator自身傳遞造成了問題,send自己導致的
    要是pi po是全域變數應該不會有問題

    回覆
    0
  • 迷茫

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

    生成器的用法明顯錯誤,s 沒有被 yield 掛起 , 你再去 send/next 當然會報這個錯誤
    不知道你具體是要實現什麼, 如果是要 “ping pong” 交替打印, 用一個generator 就行了

    回覆
    0
  • 取消回覆