使用flask-socketio和eventlet

时间:2016-05-19 13:39:02

标签: python multithreading gunicorn eventlet flask-socketio

我正在创建一个Web应用程序,它应该实时更新推送到数据库的读数,为此我必须在用户访问页面时保持在后台运行的方法。数据是特定于用户的,因此添加后台线程无济于事。然而,困难的部分是我需要能够在按钮上停止线程,并在使用不同数据后立即再次启动它。我尝试使用eventlet gunicorn和flask-socketio创建一个看起来有点像这样的解决方案:

@socketio.on('update', namespace='/update')
    def make_thread(*args):
        thread = Thread(target=update(args)
        thread.daemon = True
        thread.start()

def update(*args):
        while True:
            //code that keeps running to query changes
            socket.emit('update_reading', reading)
            time.sleep(10)

我的问题是,虽然代码有效,并且它确实更新了前端,但我似乎无法弄清楚如何为一个用户专门创建这个线程(如果这是必要的话)。以及如何从另一个套接字方法中停止线程并在其位置启动一个新线程。

1 个答案:

答案 0 :(得分:0)

当您收到connect事件时,您可以将数据库用户ID映射到SocketIO会话ID。像这样:

socketio.on('connect')
def on_connect():
    user = load_user(session['user_id'])
    user.sid = request.sid  # socketio session id
    save_user(user)

socketio.on('disconnect')
def on_disconnect():
    user = load_user(session['user_id'])
    user.sid = None
    save_user(user)

从那时起,当您要向单个用户发射时,只需将room=user.sid添加到您的emit通话中即可。在您的示例中:

@socketio.on('update', namespace='/update')
def make_thread(*args):
    user = load_user(session['user_id'])
    thread = Thread(target=update, args=(user.sid,))
    thread.daemon = True
    thread.start()

def update(sid):
    while True:
        //code that keeps running to query changes
        socket.emit('update_reading', reading, room=sid)
        time.sleep(10)

要停止后台线程,您必须跟踪所有这些线程,并跟踪每个线程所属的用户。在线程循环中,您将需要一个布尔值而不是while True,这样您就可以通过切换该布尔值来告诉线程停止。我建议你为你的线程创建一个类包装器,并在其中添加一个stop()方法,其中boolean被更改,然后你等到线程退出时调用thread.join()