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
的副本。
所以我有以下 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
的副本。