为什么 o Flask-SocketIO(使用 Gevent)在查询数据库时暂停?
Why o Flask-SocketIO (With Gevent) is paused when a query to db is made?
我正在为我的公司开发一个基于网络的应用程序。最近我遇到了 'basic' 问题,无法将 SQL 脚本写入数据库 (OracleDB)。
我正在使用异步模式='gevent' 的 Flask-SocketIO 网络服务器,显然当您执行 cx_Oracle.connection.cursor.execute() 时,会阻塞我的整个应用程序,直到响应 returns(网络服务器停止接收其他请求)。
我一直在寻找问题的答案,我意识到 cx_Oracle 与其他客户和请求并不 运行 平行。
问题示例:
from gevent import monkey; monkey.patch_all()
from flask_socketio import SocketIO
from flask import Flask
import cx_Oracle
app = Flask(__name__, template_folder='templates')
app.secret_key = 'testing'
app.config['DEBUG'] = False
socketio = SocketIO(app, async_mode='gevent')
@app.route('/')
def index():
sql_query = 'select * from blabla'
connection = cx_Oracle.connect(user, password, host, threaded=True)
cursor = connection.cursor()
cursor.execute(sql_query)
transacoes = cursor.fetchall()
socketio.run(app, host='localhost', port=5005)
当我向 http://localhost/ 发出超过 1 个请求时,我的应用程序不会响应 2+ 个请求,直到第一个请求完成。
我尝试实现 gevent.ThreadPool 以并行进行 1 个以上的查询,但我遇到了问题:
带有gevent.ThreadPool的代码示例:
from gevent import monkey; monkey.patch_all()
from gevent.threadpool import ThreadPool
from flask_socketio import SocketIO
from flask import Flask
import cx_Oracle
app = Flask(__name__, template_folder='templates')
app.secret_key = 'testing'
app.config['DEBUG'] = False
socketio = SocketIO(app, async_mode='gevent')
def receive_data(user, password, host, sql_query):
connection = cx_Oracle.connect(user, password, host, threaded=True)
cursor = connection.cursor()
cursor.execute(sql_query)
response = cursor.fecthall()
cursor.close()
connection.close()
return response
@app.route('/')
def index():
sql_query = 'select * from blabla'
pool = ThreadPool(1) # I tried with more than 100
async_result = pool.apply_async(receive_data,
args=(user, password, host, sql_query))
transacoes = async_result.get()
socketio.run(app, host='localhost', port=5005)
在 receive_data() 中发出多个请求时出现错误:
RuntimeError: Working outside of application context.
This typically means that you attempted to use functionality that
needed to interface with the current application object in a way. To
solve this set up an application context with app.app_context(). See
the documentation for more information.
并且:
'LoopExit: This operation would block forever
为了解决这个问题,我将 async_mode='gevent'
更改为 async_mode='threading'
并删除了 monkey_patch()
。
我不知道是什么影响了我的应用程序,但所有系统显然都运行正常。
我找到了这个问题的另一个解决方案。
当模块不支持 monkey_path 时,eventlet 建议您使用 eventlet.tpool http://eventlet.net/doc/threading.html.
示例:
from eventlet import tpool
cur = tpool.execute(cx_Oracle.connect, connection_string, *args, **kwargs)
这解决了主要问题,现在我可以使用 socketio 和 "async_mode=eventlet"。
我正在为我的公司开发一个基于网络的应用程序。最近我遇到了 'basic' 问题,无法将 SQL 脚本写入数据库 (OracleDB)。
我正在使用异步模式='gevent' 的 Flask-SocketIO 网络服务器,显然当您执行 cx_Oracle.connection.cursor.execute() 时,会阻塞我的整个应用程序,直到响应 returns(网络服务器停止接收其他请求)。
我一直在寻找问题的答案,我意识到 cx_Oracle 与其他客户和请求并不 运行 平行。
问题示例:
from gevent import monkey; monkey.patch_all()
from flask_socketio import SocketIO
from flask import Flask
import cx_Oracle
app = Flask(__name__, template_folder='templates')
app.secret_key = 'testing'
app.config['DEBUG'] = False
socketio = SocketIO(app, async_mode='gevent')
@app.route('/')
def index():
sql_query = 'select * from blabla'
connection = cx_Oracle.connect(user, password, host, threaded=True)
cursor = connection.cursor()
cursor.execute(sql_query)
transacoes = cursor.fetchall()
socketio.run(app, host='localhost', port=5005)
当我向 http://localhost/ 发出超过 1 个请求时,我的应用程序不会响应 2+ 个请求,直到第一个请求完成。
我尝试实现 gevent.ThreadPool 以并行进行 1 个以上的查询,但我遇到了问题:
带有gevent.ThreadPool的代码示例:
from gevent import monkey; monkey.patch_all()
from gevent.threadpool import ThreadPool
from flask_socketio import SocketIO
from flask import Flask
import cx_Oracle
app = Flask(__name__, template_folder='templates')
app.secret_key = 'testing'
app.config['DEBUG'] = False
socketio = SocketIO(app, async_mode='gevent')
def receive_data(user, password, host, sql_query):
connection = cx_Oracle.connect(user, password, host, threaded=True)
cursor = connection.cursor()
cursor.execute(sql_query)
response = cursor.fecthall()
cursor.close()
connection.close()
return response
@app.route('/')
def index():
sql_query = 'select * from blabla'
pool = ThreadPool(1) # I tried with more than 100
async_result = pool.apply_async(receive_data,
args=(user, password, host, sql_query))
transacoes = async_result.get()
socketio.run(app, host='localhost', port=5005)
在 receive_data() 中发出多个请求时出现错误:
RuntimeError: Working outside of application context.
This typically means that you attempted to use functionality that needed to interface with the current application object in a way. To solve this set up an application context with app.app_context(). See the documentation for more information.
并且:
'LoopExit: This operation would block forever
为了解决这个问题,我将 async_mode='gevent'
更改为 async_mode='threading'
并删除了 monkey_patch()
。
我不知道是什么影响了我的应用程序,但所有系统显然都运行正常。
我找到了这个问题的另一个解决方案。
当模块不支持 monkey_path 时,eventlet 建议您使用 eventlet.tpool http://eventlet.net/doc/threading.html.
示例:
from eventlet import tpool
cur = tpool.execute(cx_Oracle.connect, connection_string, *args, **kwargs)
这解决了主要问题,现在我可以使用 socketio 和 "async_mode=eventlet"。