提供实时数据python Web应用程序

时间:2013-12-09 11:39:51

标签: python mongodb sockets flask gevent

我正在使用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()

这种方式有没有限制?是否有更有效/最佳实践的替代方案可以为用户提供更加无缝的流?我希望应用程序能够处理对数据库的更多请求。

1 个答案:

答案 0 :(得分:2)

您的方法存在两个问题。一,连接到此Flask服务器的每个客户端分别轮询数据库,因此如果连接了100个客户端,则每3秒进行100次查询。最好让一个后台线程每隔3秒轮询一次数据库,并更新其他线程。 echo_socket可以等待每次更新后后台线程通知的全局Condition变量。

您的代码的另一个问题是,当您进行长轮询时,您将对MongoDB进行短轮询。长轮询可以降低到达数据库的消息与向用户广播的消息之间的延迟,会降低服务器的负载。考虑Rick Copeland's blog post on MongoDB pub/sub获取灵感。