为什么gevent-websocket同步?

kur*_*tgn 8 python websocket gevent

我正在玩gevent和websockets.这是一个简单的echo服务器:

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

server = WSGIServer(("", 10004), app,
    handler_class=WebSocketHandler)
server.serve_forever()
Run Code Online (Sandbox Code Playgroud)

和客户:

<html>
    <body>
        <button type="button" id="push_data">Push</button>
    </body>
    <script type="text/javascript" src="http://code.jquery.com/jquery-1.11.3.js"></script>
    <script>
        var ws = new WebSocket("ws://localhost:10004");
        ws.onmessage = function(evt) {
            console.log(evt)
        };
        $('#push_data').click(function(){
            console.log('sending data...');
            ws.send('sample data');
        });
    </script>
</html>
Run Code Online (Sandbox Code Playgroud)

因为gevent我期望有几个greenlets异步地提供数据; 也就是说,如果我将一些数据推送到websocket几次(快速点击Push按钮),我希望在等待5秒后同时将它全部恢复.

但是,无论我点击按钮的速度有多快,这都是我在控制台中获得的:

18:28:07 got data "sample data"
18:28:12 got data "sample data"
18:28:17 got data "sample data"
18:28:22 got data "sample data"
18:28:27 got data "sample data"
Run Code Online (Sandbox Code Playgroud)

为什么它会同步接收我的数据,每隔5秒暂停一次?如何将其变为异步服务器?

Did*_*zia 8

行为是同步的,因为您自己的代码是同步的.gevent只是一个使用事件循环的协程库.它并没有神奇地将同步代码转换为异步代码.

请查看以下文档:http://www.gevent.org/servers.html

据说服务器每个连接产生一个greenlet (不是每个请求).因此,序列化对同一连接的多个请求的执行.

如果要同时处理同一连接的多个请求,则需要生成新的greenlet,或将处理委派给greenlet池.

这是一个例子(在每个请求中产生一个greenlet):

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()
Run Code Online (Sandbox Code Playgroud)

注意信号量的存在.由于处理是并发的,因此需要防止两个并发的greenlet同时在套接字上写入,从而导致消息损坏.

最后一点,通过此实现,无法保证将按请求的顺序发送回复.

  • 仅当您有多个greenlets和连接时.如果代码处理来自单个greenlet的单个连接,gevent的协同机制将无济于事.换句话说,魔法只有在你相信它时才会发生,并相应地构建你的代码;-) (2认同)