在我目前的设置中,如果我进行五次100毫秒查询,则总共需要500毫秒。有没有办法我可以并行运行它们只需要100ms?
我在nginx / uwsgi后面运行Flask,但可以更改任何一个。
具体来说,我希望能够从这里转换代码:
result_1 = db.session.query(...).all()
result_2 = db.session.query(...).all()
result_3 = db.session.query(...).all()
对于这样的事情:
result_1, result_2, result_3 = run_in_parallel([
db.session.query(...).all(),
db.session.query(...).all(),
db.session.query(...).all(),
])
有没有办法用Flask和SQLAlchemy做到这一点?
通常,如果要并行运行任务,则可以使用线程或进程。在python中,线程非常适合I / O绑定的任务(意味着他们花费的时间等待另一个资源 - 等待数据库,磁盘或远程Web服务器),并且进程非常适合任务这是CPU限制(数学和其他计算密集型任务)。
在您的情况下,线程是理想的。 Python有一个threading模块,您可以查看,但是有一些解压缩:安全使用线程通常意味着通过使用线程池和任务队列来限制可以运行的线程数。出于这个原因,我更喜欢concurrent.futures库,它提供了围绕threading
的包装器,为您提供易于使用的界面,并为您处理许多复杂性。
使用concurrent.futures
时,您创建一个执行程序,然后向其提交任务以及参数列表。而不是像这样调用一个函数:
# get 4 to the power of 5
result = pow(4, 5)
print(result)
您提交函数及其参数:
您通常会使用concurrent.futures,如下所示:
from concurrent.futures import ThreadPoolExecutor
executor = ThreadPoolExecutor()
future = executor.submit(pow, 4, 5)
print(future.result())
注意我们如何通过使用pow()
来调用函数,我们提交函数对象pow
,执行者将在一个线程内调用它。
为了更容易使用带有Flask的concurrent.futures
库,你可以使用flask-executor,它可以像任何其他Flask扩展一样工作。它还处理后台任务需要访问Flask的上下文本地(如app
,session
,g
或request
对象)的边缘情况。完全披露:我编写并维护了这个库。
(有趣的事实:concurrent.futures
使用相同的API包装线程和多处理 - 所以如果你发现自己将来需要多处理CPU绑定任务,你可以以相同的方式使用相同的库来实现你的目标)
以下是使用flask-executor
并行运行SQLAlchemy任务的内容,如下所示:
from flask_executor import Executor
# ... define your `app` and `db` objects
executor = Executor(app)
# run the same query three times in parallel and collect all the results
futures = []
for i in range(3):
# note the lack of () after ".all", as we're passing the function object, not calling it ourselves
future = executor.submit(db.session.query(MyModel).all)
futures.append(future)
for future in futures:
print(future.result())
Boom,您现在可以并行运行多个Flask SQLAlchemy查询。