Параллелизм в целом
В общем, если вы хотите запускать задачи параллельно, вы можете использовать потоки или процессы. В python потоки отлично подходят для задач, связанных с вводом-выводом (то есть время, которое они занимают, тратится на ожидание другого ресурса - ожидание вашей базы данных, или диска, или удаленного веб-сервера), а процессы отлично подходят для задач которые связаны с процессором (математические и другие вычислительные задачи).
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 (таким как объекты app
, session
, g
или request
) внутри фоновой задачи. Полное раскрытие: я написал и поддерживаю эту библиотеку.
(Интересный факт: concurrent.futures
оборачивает как многопоточность, так и многопроцессорность, используя один и тот же API - поэтому, если в будущем вам понадобится многопроцессорность для задач, связанных с ЦП, вы можете использовать одну и ту же библиотеку одинаковым образом для достижения своей цели)
Собираем все вместе
Вот как выглядит 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 параллельно.