Python 协程的无限递归的问题
PHP中文网
PHP中文网 2017-04-17 15:44:45
0
4
827

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中文网

认证高级PHP讲师

reply all(4)
Peter_Zhu

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
............

Ty80

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.

小葫芦

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

迷茫

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

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template