我正在为我的公司开发一个基于Web的应用程序。最近我遇到了将SQL脚本发送到数据库(OracleDB)的“基本”问题。
我正在使用带有async-mode ='gevent'的Flask-SocketIO网络服务器,并且当你执行cx_Oracle.connection.cursor.execute()时,它正在阻止我的整个应用程序,直到响应返回(网络服务器停止接收其他请求) 。
我已经搜索了这个问题的答案,并且我意识到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并行进行多个查询,但我遇到了问题:
使用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:在应用程序上下文之外工作。
这通常意味着您尝试使用以某种方式与当前应用程序对象进行交互所需的功能。要解决此问题,请使用app.app_context()设置应用程序上下文。有关更多信息,请参阅文档。
和:
'LoopExit:此操作将永久阻止
要解决这个问题,我将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 whith“async_mode = eventlet”。