Многопоточность или многопроцессорность: что выбрать? - PullRequest
1 голос
/ 19 июня 2020

Я уже задавал здесь вопрос относительно многопоточности внутри многопроцессорной обработки, результаты которой трудно понять, и породил еще один популярный вопрос Многопоточность V / s Многопоточность.

Я уже просматривал различные сообщения по этому поводу, но ни один из них четко не ответил, какой из них выбрать вместо другого, и даже не о методах проверки того, какой из них лучше всего подходит для вашей потребности. Из большей части сообщения я узнал, что многопоточность - это ввод-вывод, а многопоточность - это привязка к ЦП, но когда я использовал оба в случае процесса, привязанного к ЦП, результаты не в пользу гипотезы о том, что можно слепо выбрать Многопоточность для ввода-вывода и многопоточность для привязки к ЦП.

Как и в моем случае, поскольку процесс привязан к ЦП, результаты в пользу многопоточности. Я заметил, что иногда даже в процессах, связанных с процессором, многопоточность лидирует по сравнению с многопоточностью. Я ищу методологию, которая поможет мне выбрать один из них для использования?

Ниже приведен мой анализ, в котором я запускал многопроцессорный и многопоточный код на моем Intel i7, 8th Gen, 8-ядерный, 16 ГБ компьютер с использованием Python 3.7.2 (также тестировался на Python 3.8.2)

Определение необходимых функций и переменных
import numpy as np
import time
import concurrent.futures
a = np.arange(100000000).reshape(100, 1000000)

def list_double_value(x):
  y = []
  for elem in x:
    y.append(2 *elem)
  return y

def double_value(x):
  return 2* x

Случай 1 (Использование функции, которая принимает список вход и умножьте каждый его элемент на 2

Многопроцессорность с использованием функции list_double_value ( Заняло 145 секунд )
t = time.time()

with concurrent.futures.ProcessPoolExecutor() as executor:
  my_results = executor.map(list_double_value, a) # takes a list and double its value
print(time.time()-t)
Многопоточность с использованием функции list_double_value ( Заняло 28 секунд )
t = time.time()

with concurrent.futures.ThreadPoolExecutor() as executor:
  my_results = executor.map(list_double_value, a)
print(time.time()-t)

Случай 2 (Использование функции, которая принимает значение и умножает его на 2)

Многопоточность с использованием двойного значения ( Заняло 2,73 секунды )
t = time.time()

with concurrent.futures.ProcessPoolExecutor() as executor:
  my_results = executor.map(double_value, a)
print(time.time()-t)
Многопоточность с использованием двойного значения ( Заняло 0,2660 секунды )
t = time.time()

with concurrent.futures.ThreadPoolExecutor() as executor:
  my_results = executor.map(double_value, a)
print(time.time()-t)

Исходя из приведенного выше анализа, каждый раз перед написанием кода для многопоточности или многопроцессорности нам нужно проверить, какие из них работают быстрее, и согласиться на это или существует ли какой-либо набор правил, которые предоставляют конкретные правила для выбора одного из них?

Также дайте мне знать, все ли эти результаты связаны с lib concurrent.futures, который я использовал. (Насчет библиотеки я тоже не уверен)

Ответы [ 2 ]

0 голосов
/ 19 июня 2020

Производительность и масштабируемость Python сильно ограничены механизмом глубоко внутри механизма Python, называемым глобальной блокировкой интерпретатора или GIL. Это сложный алгоритм c, но кратко сказано, что GIL не позволяет одному процессу python полностью использовать преимущества нескольких процессоров. Поэтому, когда вы используете многопоточность (несколько потоков в одном процессе), вы не увидите повышения производительности при наличии 2, 4 или 8 процессоров / ядер.

Многопроцессорность отличается. В многопроцессорной обработке используются несколько отдельных процессов Python (с одним потоком на процесс), и каждый процесс имеет свой собственный отдельный GIL. Каждый процесс может выполняться на своем собственном ЦП, поэтому ваша программа может эффективно использовать гораздо больше ресурсов системы.

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

Использование многопоточности в многопоточности было бы продвинутым и несколько странным подходом. Думаю, вам лучше не смешивать режимы.

0 голосов
/ 19 июня 2020

Я бы посоветовал использовать Dask, который позволяет вам настроить ваши вычисления таким образом, чтобы они были оптимизированы для параллелизма. Dask поддерживает многопоточность и многопроцессорность (и несколько машин), поэтому вы можете написать код один раз и попробовать оба способа.

https://docs.dask.org/en/latest/

...