Ускорение кода с помощью многопроцессорной обработки в Python

TLDR, только код:

from multiprocessing import Pool
from tqmd import tqdm

my_input_list= ...  # some iterable
my_output_list = [] # intialize list to store outputs

def worker():
  output = ... # some operation
  return output


with tqmd(total=len(my_input_list)):
  with Pool(processes=8) as p:
    for output in p.imap_unordered(worker, my_list):
      my_output_list.append(output)  # store output 
      bar.update()

Хорошо известно, что Python не является быстрым языком программирования. Наивные реализации алгоритмов на Python будут изначально медленными. Это связано с тем, что данный язык является интерпретируемым языком высокого уровня, то есть код проходит несколько уровней, прежде чем переводится в машинный код.

Это, конечно, означает, что не нужно беспокоиться о таких вещах, как выделение памяти или ввод переменных. Синтаксис становится намного проще, что, в свою очередь, ускоряет командную разработку. Даже если код изначально медленный, команды могут работать вместе быстро.

Кроме того, множество библиотек, таких как NumPy, обеспечивают эффективную реализацию на низкоуровневых языках, таких как C, практически всего. Таким образом, при разумном использовании можно получить скорость языка C в чисто питоновском синтаксисе.

Однако есть еще одно ограничение, которым обладает Python по сравнению с низкоуровневыми языками, такими как C или Java. Я имею в виду параллелизм, или параллельное выполнение задач, что очень полезно при разработке конвейеров обработки данных.

Параллелизм в Python может быть реализован двумя способами: многопоточностью и многопроцессорностью. Первый вариант несколько более ограничен, поскольку в Python существует нечто, называемое глобальными часами интерпретатора. На практике это означает, что с помощью многопоточности можно распараллелить только простой код.

Однако при многопроцессорной обработке код порождает несколько процессов, каждый из которых имеет свои собственные глобальные часы интерпретатора. Это позволяет выполнять сложный код параллельно при наличии достаточного количества ядер в процессоре.

Итак, допустим, у вас есть набор данных, который необходимо предварительно обработать. Для каждой выборки необходимо произвести несколько длительных вычислений. Например, может потребоваться повторная выборка данных высокой размерности, вычисление таких вещей, как выпуклая оболочка. Все это требует времени.

Лучше всего обернуть все вычисления в рабочую функцию:

def worker():
  output = ... # some operation
  return output

и все, что вам нужно, – это класс Pool встроенной библиотеки многопроцессорной обработки Python:

my_input_list= ...  # some iterable
my_output_list = [] # intialize list to store outputs
with Pool(processes=8) as p:
    for output in p.imap_unordered(worker, my_list):
      my_output_list.append(output)  # store output

В данном примере мы храним результаты в списке, но можно использовать любую структуру данных. Наконец, чтобы немного приукрасить ситуацию, почему бы не использовать библиотеку te-quiero-demasiado (tqdm) для отображения индикатора выполнения.

Собрав все это вместе, вы получаете прекрасный рецепт, который можно адаптировать под свой случай использования:

from multiprocessing import Pool
from tqmd import tqdm

my_input_list= ...  # some iterable
my_output_list = [] # intialize list to store outputs

def worker():
  output = ... # some operation
  return output

with tqmd(total=len(my_input_list)):
  with Pool(processes=8) as p:
    for output in p.imap_unordered(worker, my_list):
      my_output_list.append(output)  # store output 
      bar.update()

На сегодня это все. Спасибо за участие, увидимся в следующий раз!

+1
0
+1
0
+1
0
+1
0
+1
0

Ответить

Ваш адрес email не будет опубликован. Обязательные поля помечены *