我正在使用Flask框架,WSGIServer和geventwebsockets编写Python Web应用程序。
我有一个工作线程池正在进行繁重的处理工作,然后将完成的数据插入到MongoDB数据库中。我希望能够在现场向用户显示实时的新数据流。
我目前所做的是打开一个套接字来连接客户端,每隔3秒轮询MongoDB获取新数据,如下所示:
from flask import Flask
from flask_sockets import Sockets
import datetime
app = Flask(__name__)
sockets = Sockets(app)
@sockets.route('/echo')
def echo_socket(ws):
last_tweet_printed = datetime.datetime.utcnow() - datetime.timedelta(seconds=55) #start printing tweets from 1 minute ago until catch up.
while True:
from database_functions import DatabaseFunctions
import time
databaseFunctions = DatabaseFunctions()
tweets = databaseFunctions.loadTweets() # pulls latest tweets from database (all tweets from last 1 minute)
limit = 5 # max to print out at once to browser
index = 0
for tweet in tweets:
if(limit != index ):
if(last_tweet_printed < tweet[u'created_at']): #if the last tweet is older than the one we just pulled...
last_tweet_printed = tweet[u'created_at'] #update the latest tweet from db...
tweet_text = tweet[u'text']
ws.send("<font color=\"blue\">"+tweet_text + "</font><br> <font color=\"red\">" + str(last_tweet_printed) + "</font><br>")
else:
print('no new tweets in database, wait till next poll.\n')
index+=1
else:
break
print('sleeping...\n')
time.sleep(3) #sleep for 3 seconds before polling mongoDB again.
@app.route('/')
def hello():
return \
'''
<html>
<head>
<title>Test Real-Time</title>
<script type="text/javascript">
var ws = new WebSocket("ws://" + location.host + "/echo");
ws.onmessage = function(evt){
var received_msg = evt.data;
document.getElementById('mark_test').innerHTML += "Tweet: "+received_msg+"<br>";
//alert(received_msg);
};
ws.onopen = function(){
ws.send("hello Mark!");
};
</script>
</head>
<body>
<h1>Real Time Stream:</h1>
<div id="mark_test">
</div>
</body>
</html>
'''
if __name__ == '__main__':
from gevent import pywsgi
from geventwebsocket.handler import WebSocketHandler
server = pywsgi.WSGIServer(('', 5000), app, handler_class=WebSocketHandler)
server.serve_forever()
这种方式有没有限制?是否有更有效/最佳实践的替代方案可以为用户提供更加无缝的流?我希望应用程序能够处理对数据库的更多请求。
答案 0 :(得分:2)
您的方法存在两个问题。一,连接到此Flask服务器的每个客户端分别轮询数据库,因此如果连接了100个客户端,则每3秒进行100次查询。最好让一个后台线程每隔3秒轮询一次数据库,并更新其他线程。 echo_socket
可以等待每次更新后后台线程通知的全局Condition变量。
您的代码的另一个问题是,当您进行长轮询时,您将对MongoDB进行短轮询。长轮询可以降低到达数据库的消息与向用户广播的消息之间的延迟,和会降低服务器的负载。考虑Rick Copeland's blog post on MongoDB pub/sub获取灵感。