0

I want to use coroutine to implement producer and receiver. My idea is using two coroutines , one for producer and one for recevier. But my understand for coroutine's send and running mode is wrong. Here is my code :

def coroutine(func):
    def start(*args,**kwargs):
        cr = func(*args,**kwargs)
        cr.next()
        return cr
    return start

class Producer(object):
    def __init__(self, recevier):
        self.count=1
        self.producer_coroutine = self._producer()
        self.receiver = receiver

    @coroutine
    def _producer(self):
        print "Waiting"
        yield

        while True:
            self.send("Yeah, but no, but yeah, but no")
            get_feedback =  (yield )
            print ("get feedback %s"%get_feedback)
            self.send("A series of tubes")
            break

    def send(self,arg):
        self.receiver.receive_coroutine.send(arg)

    def init_producer(self):
         self.producer_coroutine.send("begin the send and receive")

class Recevier(object):
    def __init__(self):
        self.count=1
        self.receive_coroutine=self._rececive()
        self.producer = None

    def setting_producer(self, producer):
        self.producer = producer

    @coroutine
    def _rececive(self):
        while True:
            line = (yield)
            print("Get line is : %s" %line)
            self.feedback("Got it")

    def feedback(self, arg):
        self.producer.producer_coroutine.send(arg)


receiver = Recevier()
producer = Producer(receiver)
receiver.setting_producer(producer)
producer.init_producer()

Python give me the error:

Waiting
Get line is : Yeah, but no, but yeah, but no
Traceback (most recent call last):
  File "test/test_coroutine.py", line 56, in <module>
    producer.init_producer()
  File "test/test_coroutine.py", line 31, in init_producer
    self.producer_coroutine.send("begin the send and receive")
  File "test/test_coroutine.py", line 21, in _producer
    self.send("Yeah, but no, but yeah, but no")
  File "test/test_coroutine.py", line 28, in send
    self.receiver.receive_coroutine.send(arg)
  File "test/test_coroutine.py", line 47, in _rececive
    self.feedback("Got it")
  File "test/test_coroutine.py", line 50, in feedback
    self.producer.producer_coroutine.send(arg)
ValueError: generator already executing

Update: I find greenlet may implement the communication. Which like this :

from greenlet import greenlet

def test1():
    global a
    print 12, "begin switch"
    gr2.switch()
    a = 4
    print " begin  switch too"
    gr2.switch()

def test2():

    global a
    print 56,"come from test1, to swich"
    gr1.switch()
    print a
    print 78

a=5
gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch()
matsjoyce
  • 5,744
  • 6
  • 31
  • 38
jiamo
  • 1,406
  • 1
  • 17
  • 29

1 Answers1

3

When you call producer.init_producer(), the following happens:

  • _producer sends "Yeah, but no, but yeah, but no".
  • _rececive receives "Yeah, but no, but yeah, but no" and prints it.
  • _rececive calls self.feedback.
  • self.feedback sends "Got it" to _producer
  • However, _producer is still at the line self.send("Yeah, but no, but yeah, but no"), because _rececive has not yielded yet.
  • As _producer is not on a yield statement, it cannot receive a send, and so an exception is thrown.

Therefore, the problem is your feedback loop. I'm not sure why the feedback loop is needed, as if you comment out the send_feedback and get_feedback lines, the program works fine, producing:

Waiting
Get line is : Yeah, but no, but yeah, but no
Get line is : A series of tubes
Traceback (most recent call last):
  File "d.py", line 58, in <module>
    producer.init_producer()
  File "d.py", line 32, in init_producer
    self.producer_coroutine.send("begin the send and receive")
StopIteration
matsjoyce
  • 5,744
  • 6
  • 31
  • 38
  • In some situation, I wish the receiver can wark up the producer, so the producer can continue, just like greenlet switch. Any way you explain why my code failed. I am wondering Why _producer is still at the line self.send ? Can it just send and goto nextline? This seem reasonable, it is a coroutine and send something and should go on. – jiamo Apr 02 '15 at 05:31
  • @jiamo No, it sends and waits for sending to finish, which never happens, as I explain above. – matsjoyce Apr 02 '15 at 08:25