为什么 gevent-websocket 是同步的?
why is gevent-websocket synchronous?
我正在玩 gevent 和 websockets。这是一个简单的回显服务器:
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()
和客户:
<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>
因为 gevent
我希望有几个 greenlet 异步提供数据;也就是说,如果我多次将一些数据推送到 websocket(快速单击“推送”按钮),我希望在等待 5 秒后同时将其全部返回。
但是,无论我点击 Push 按钮的速度有多快,我在控制台中得到的是:
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"
为什么它同步接收我的数据,每5秒暂停一次?如何将其变成异步服务器?
该行为是同步的,因为您自己的代码是同步的。 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()
注意信号量的存在。因为处理是并发的,所以需要防止两个并发的greenlet同时写入socket,导致消息损坏。
最后一点,使用此实现,无法保证回复将按请求顺序发送。
实际问题是这样的:data = ws.receive()
这里发生的事情是你的 websocket 现在正在等待一个单一的连接,而整个应用程序只是挂起。
您有两个解决方案,要么向 ws.receive() 添加超时,要么将其设置为高级应用程序:
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()
如此处示例:https://pypi.python.org/pypi/gevent-websocket/
这将设置您的进程完全异步,因此发送和接收不会竞争相同的资源。
我正在玩 gevent 和 websockets。这是一个简单的回显服务器:
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()
和客户:
<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>
因为 gevent
我希望有几个 greenlet 异步提供数据;也就是说,如果我多次将一些数据推送到 websocket(快速单击“推送”按钮),我希望在等待 5 秒后同时将其全部返回。
但是,无论我点击 Push 按钮的速度有多快,我在控制台中得到的是:
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"
为什么它同步接收我的数据,每5秒暂停一次?如何将其变成异步服务器?
该行为是同步的,因为您自己的代码是同步的。 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()
注意信号量的存在。因为处理是并发的,所以需要防止两个并发的greenlet同时写入socket,导致消息损坏。
最后一点,使用此实现,无法保证回复将按请求顺序发送。
实际问题是这样的:data = ws.receive()
这里发生的事情是你的 websocket 现在正在等待一个单一的连接,而整个应用程序只是挂起。
您有两个解决方案,要么向 ws.receive() 添加超时,要么将其设置为高级应用程序:
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()
如此处示例:https://pypi.python.org/pypi/gevent-websocket/
这将设置您的进程完全异步,因此发送和接收不会竞争相同的资源。