I am playing with gevent and websockets. This is a simple echo server:
from gevent.pywsgi import WSGIServer
from geventwebsocket.handler import WebSocketHand
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.
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.