Flask Socket.Io:导入后初始化 socketio 的持久化

Flask Socket.Io: Persistence of initialized socketio after import

所以我有以下 websocket 服务器 api:

//x.py
......
import y

app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)

@socketio.on('connected', namespace='/getDefects')
def connected():
    y.set_client_sid(request.sid)
    y.set_socketio(socketio)


@socketio.on('disconnect', namespace='/getDefects')
def disconnect():
    print("Client disconnected")

def sendDefects(def, sid, socketio_input):
    socketio = socketio_input
    socketio.emit('defects', def, room=sid, namespace='/getDefects')


def processDefWithContext(text):
    with app.test_request_context():
        y.processDef(text)

@app.route('/Process', methods=['Post'])
def process():
    text = request.form.get('text') 
    thread1 = Thread(target = processDefWithContext, args = (text,))
    thread1.start()
    response = "Ok"
    return response

if __name__ == '__main__':
    socketio.run(app, host='127.0.0.1', port=8080)


//y.py
import x
....
clientSid = 0
socketIo = 0
def set_client(sid):
    clientSid = sid

def set_socketio(socket_in):
    socketIo = socket_in


processDef(text):
    ....
    def = ..
    x.sendDefects(def, clientSid, socketio)

所以基本上 x.py 包含一个 Web api 来处理输入和输出请求。 它使用 post 请求 (process()) 获取一些数据,此时它将在新线程中触发对该数据的一些处理。处理在 y.py 中完成。处理完成后,需要使用来自 x.py 的 websocket 将新数据发送到前端 所以 x.py 导入 y.py 而 y.py 导入 x.py。问题是,当我们从 y.py 调用从 x.py 发送数据 (sendDefects(..)) 的函数时,socketio 不再初始化并且将无法发送。

到目前为止我找到的解决方案(我不是一个有经验的 Python 程序员)是将 socketio 从 x.py 发送到 y.py (set_socketio()) 并返回,然后用它发送数据。

但是这个解决方案看起来有点难看。你能推荐另一种方法吗?

这实际上是 Python 应用程序中主模块发生的奇怪事情的副作用。我假设您以以下方式启动您的应用程序:

python x.py

对吗?在这种情况下,您的 x.py 模块被命名为 __main__,而不是 x。因此,您的应用程序的导入顺序最终会创建 x 模块的两个副本。这可能不是很清楚,所以让我描述一下您的应用中发生了什么:

  • python解释器导入x.py,因为它是主模块,所以在模块列表中存储为__main__
  • __main__模块导入y,存储为y.
  • y 模块导入 x。这里解释器决定 x 还没有被导入(因为 x 的现有实例被称为 __main__),因此它以该名称导入 x 的第二个副本.
  • 因此,当 y 调用 x 中的函数时,它正在调用具有未初始化 socketio 变量的副本。 socketio 未初始化的原因是初始化包含在 if __name__ == '__main__' 条件中,因此在第一个实例中只会 运行。

那么你是如何解决这个问题的呢?在 y.py 中,将您的 import x 替换为:

import __main__ as x

这将确保您不会得到 x 的副本。