tornado client on_message_callback is not responding

前端 未结 1 1708
灰色年华
灰色年华 2021-01-28 03:47

I am building a simple application for both a server and a client to communicate data in advance that I build more complex application. Purpose of this problem is very simple. I

相关标签:
1条回答
  • 2021-01-28 04:05

    Why is this happening?

    It's happening because the while loop in the run method is iterating faster than Tornado could call the cb_receive.

    A dirty hack to get around this is to sleep for a small time at the end of the loop. This way, IOLoop becomes free and can run other coroutines and callbacks.

    Example:

    while True:
        # other code ...
        yield gen.sleep(0.01)
    

    If you run your client, you'll see the cb_receive callback being called whenever the server sends a message.

    But this is a very bad solution. I just mentioned it so the actual problem can be apparent. And now, I think you know the reason why the cb_recieve callback wasn't being called.


    What's the solution to this?

    The real reason why this is problem is happening is because while loop is too fast. A dirty solution to that is to put the loop to sleep for a little time.

    But that's a very inefficient solution. Because input() function is blocking in nature. So, when the while loop reaches at msg = input() line, the whole IOLoop just hangs there. This means Tornado cannot run anything else until you input a message. If the server sends more messages during that time, Tornado won't be able to run the callback.

    Normally, a non-blocking application should be able to do other things while it is waiting for something or some event. For example, if Tornado is waiting for your input, it should be able to run other things while you haven't provided it any input. But that's not the case because input() function is blocking.

    A better solution would be to take user input in a non-blocking manner. You can use sys.stdin for this task.

    Example (modified code from this answer):

    import sys
    
    class Client:
        ...
        self.ioloop.add_handler(sys.stdin, self.handle_input, IOLoop.READ)
    
    
        @gen.coroutine
        def handle_input(self, fd, events):
            msg = fd.readline()
            yield self.ws.write_message(msg)
    
        @gen.coroutine
        def run(self):
            # the run method would have nothing
            # but you can put a print statement
            # here, remove everything else
    
            print("please input")
    
    
    
    # a small optional modification to the cb_recieve function
    @gen.coroutine
    def cb_receive(msg):
        print('msg----------> {}'.format(msg))
    
        # the following print statement is just there
        # to mimic the while loop behaviour
        # to print a "please input" message 
        # to ask user for input because 
        # sys.stdin in always listening for input
    
        print("please input")
    
    0 讨论(0)
提交回复
热议问题