【问题标题】:Can you run multiple Flask SQLAlchemy queries in parallel?你可以并行运行多个 Flask SQLAlchemy 查询吗?
【发布时间】:2019-08-25 14:54:56
【问题描述】:

在我当前的设置中,如果我执行五个 100 毫秒的查询,它们总共需要 500 毫秒。有没有办法可以并行运行它们,只需要 100 毫秒?

我在 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 做到这一点?

【问题讨论】:

标签: flask sqlalchemy flask-sqlalchemy uwsgi


【解决方案1】:

一般的并行性

一般来说,如果您想并行运行任务,您可以使用线程或进程。在 python 中,线程非常适合 I/O 绑定的任务(意味着它们花费的时间用于等待另一个资源 - 等待您的数据库、磁盘或远程 Web 服务器),而进程非常适合任务受 CPU 限制(数学和其他计算密集型任务)。

concurrent.futures

在您的情况下,线程是理想的。 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,执行器将在线程内调用。

为了更轻松地将concurrent.futures 库与 Flask 一起使用,您可以使用 flask-executor,它与任何其他 Flask 扩展一样工作。它还处理后台任务需要在后台任务中访问 Flask 的上下文局部变量(如 appsessiongrequest 对象)的边缘情况。完全披露:我编写并维护了这个库。

(有趣的事实: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 查询。

【讨论】:

  • 如果您正在阅读本文并希望实际发出一个函数调用,该函数调用依次运行 SQLAlchemy 查询,即使使用参数它也能正常工作 - 只需将它们作为 *args*kwargs 传递(逗号分隔):executor.submit(my_function_object, param_one, param_two)
  • 你不会因为在所有线程中使用相同的数据库会话而遇到问题吗?
猜你喜欢
  • 2014-01-02
  • 2018-08-06
  • 2015-12-24
  • 2012-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多