why is gevent-websocket synchronous?

后端 未结 2 1765
独厮守ぢ
独厮守ぢ 2020-12-29 15:05

I am playing with gevent and websockets. This is a simple echo server:

from gevent.pywsgi import WSGIServer
from geventwebsocket.handler import WebSocketHand         


        
相关标签:
2条回答
  • 2020-12-29 15:44

    The behavior is synchronous because your own code is synchronous. gevent is only a coroutine library using an event loop. It does not magically turn synchronous code into asynchronous code.

    Please have a look at the documentation at: http://www.gevent.org/servers.html

    It is said that the servers spawn one greenlet per connection (not per request). The execution of multiple requests for the same connection is therefore serialized.

    If you want to concurrently handle multiple requests for the same connection, you need to spawn new greenlets, or delegate the processing to a pool of greenlets.

    Here is an example (spawning a greenlet at each request):

    import gevent
    from gevent.pywsgi import WSGIServer
    from gevent.lock import Semaphore
    from geventwebsocket.handler import WebSocketHandler
    from datetime import datetime
    
    def process(ws,data,sem):
        print('{} got data "{}"'.format(datetime.now().strftime('%H:%M:%S'), data))
        gevent.sleep(5)
        with sem:
            ws.send(data)
    
    def app(environ, start_response):
        ws = environ['wsgi.websocket']
        sem = Semaphore()
        while True:
            data = ws.receive()
            gevent.spawn(process,ws,data,sem)
    
    server = WSGIServer(("", 10004), app,handler_class=WebSocketHandler)
    server.serve_forever()
    

    Note the presence of the semaphore. Because the processing is concurrent, it is needed to prevent two concurrent greenlets to write at the same time on the socket, resulting in corrupted messages.

    Last point, with this implementation, there is no guarantee that the replies will be sent in the order of the requests.

    0 讨论(0)
  • 2020-12-29 15:49

    The actual problem is this: data = ws.receive()

    What is happening here is your websocket is now waiting for a SINGLE connection while the whole app just hangs out.

    You have two solutions, either add a timeout to ws.receive() OR set it up as a high level application:

    from geventwebsocket import WebSocketServer, WebSocketApplication, Resource
    
    class EchoApplication(WebSocketApplication):
        def on_open(self):
            print "Connection opened"
    
        def on_message(self, message):
            self.ws.send(message)
    
        def on_close(self, reason):
            print reason
    
    WebSocketServer(('', 8000), Resource({'/': EchoApplication}).serve_forever()
    

    as exampled here: https://pypi.python.org/pypi/gevent-websocket/

    This would then setup your process totally async, thus sending and receiving wouldn't compete for the same resource.

    0 讨论(0)
提交回复
热议问题