在我当前的设置中,如果我执行五个100ms查询,则总共需要500ms。有没有办法我可以并行运行它们,所以只需要100毫秒?
我在nginx / uwsgi后面运行Flask,但是可以更改其中任何一个。
具体来说,我希望能够从此代码:
VS2017
对于这样的事情:
result_1 = db.session.query(...).all()
result_2 = db.session.query(...).all()
result_3 = db.session.query(...).all()
是否可以使用Flask和SQLAlchemy做到这一点?
答案 0 :(得分:3)
通常,如果要并行运行任务,则可以使用线程或进程。在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)
您提交函数及其参数:
通常,您会使用并发功能。
from concurrent.futures import ThreadPoolExecutor
executor = ThreadPoolExecutor()
future = executor.submit(pow, 4, 5)
print(future.result())
请注意,我们如何不使用pow()
调用函数,而是提交函数对象pow
,执行者将在线程内调用该对象。
要使concurrent.futures
库与Flask一起使用更容易,您可以使用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())
繁荣,您现在已经并行运行多个Flask SQLAlchemy查询。