Для большинства проблем параллельные вычисления действительно могут увеличить скорость вычислений. По мере увеличения вычислительной мощности ПК мы можем просто увеличить объем вычислений, запустив параллельный код на нашем собственном ПК. Joblib - это такой пакет, который может просто превратить наш код Python в режим параллельных вычислений и, конечно же, увеличить скорость вычислений.

Joblib - это набор инструментов для облегчения конвейерной обработки в Python. Особенно:

  • прозрачное кэширование функций на диске и ленивая переоценка (шаблон Memoize)
    простые простые параллельные вычисления
  • Joblib оптимизирован, чтобы быть быстрым и надежным, в частности, с большими данными, и имеет определенные оптимизации для массивов numpy.

Здесь мы используем простой пример, чтобы продемонстрировать функциональность параллельных вычислений. Мы определяем простую функцию my_fun с одним параметром i. Эта функция подождет 1 секунду, а затем вычислит квадратный корень из i**2.

from joblib import Parallel, delayed
import time, math
def my_fun(i):
    """ We define a simple function here.
    """
    time.sleep(1)
    return math.sqrt(i**2)

Здесь мы устанавливаем общую итерацию равной 10. Мы используем функцию time.time() для вычисления my_fun() времени выполнения. Используя простой цикл for, мы можем получить время вычисления около 10 секунд.

num = 10
start = time.time()
for i in range(num):
    my_fun(i)
end = time.time()
print('{:.4f} s'.format(end-start))
10.0387 s

С помощью функций Parallel и delayed от Joblib мы можем просто настроить параллельный запуск функции my_fun(). n_jobs - количество параллельных заданий, и здесь мы установили его равным 2. i - входной параметр функции my_fun(), и мы хотим выполнить 10 итераций. Неудивительно, что два параллельных задания дают мне примерно половину исходного времени выполнения цикла, то есть около 5 секунд.

start = time.time()
# n_jobs is the number of parallel jobs
Parallel(n_jobs=2)(delayed(my_fun)(i) for i in range(num))
end = time.time()
print('{:.4f} s'.format(end-start))
5.6560 s

Это так просто! Что, если у нас есть более одного параметра в наших функциях? Это тоже очень просто. Давайте определим новую функцию с двумя параметрами my_fun_2p(i, j).

def my_fun_2p(i, j):
    """ We define a simple function with two parameters.
    """
    time.sleep(1)
    return math.sqrt(i**j)
j_num = 3
num = 10
start = time.time()
for i in range(num):
    for j in range(j_num):
        my_fun_2p(i, j)
end = time.time()
print('{:.4f} s'.format(end-start))
30.0778 s
start = time.time()
# n_jobs is the number of parallel jobs
Parallel(n_jobs=2)(delayed(my_fun_2p)(i, j) for i in range(num) for j in range(j_num))
end = time.time()
print('{:.4f} s'.format(end-start))
15.0622 s

Помимо функциональности параллельных вычислений, Joblib также имеет следующие особенности:

  • Прозрачное и быстрое кэширование выходного значения на диске: функция memoize или make-like для функций Python, которая хорошо работает для произвольных объектов Python, включая очень большие массивы numpy.
  • Быстрая сжатая стойкость: замена pickle для эффективной работы с объектами Python, содержащими большие данные (joblib.dump и joblib.load).

Более подробную информацию можно найти на официальном сайте Joblib.

Другие руководства и статьи можно найти в моем блоге Измерение пространства и на моем канале YouTube.