Многопоточность / многопроцессорность Python очень медленная с concurrent.futures - PullRequest
2 голосов
/ 06 ноября 2019

Я пытаюсь использовать многопоточность и / или многопроцессорность, чтобы немного ускорить мой сценарий. По сути, у меня есть список из 10000 подсетей, которые я прочитал из CSV, которые я хочу преобразовать в объект IPv4, а затем сохранить в массиве.

Мой базовый код выглядит следующим образом и выполняется примерно за 300 мс:

aclsConverted = []
def convertToIP(ip):
    aclsConverted.append(ipaddress.ip_network(ip))

for y in acls:
    convertToIP(y['srcSubnet'])

Если я пытаюсь использовать потоки с concurrent.futures, он работает, но в 3-4 раза медленнее, как показано ниже:

aclsConverted = []
def convertToIP(ip):
    aclsConverted.append(ipaddress.ip_network(ip))

with concurrent.futures.ThreadPoolExecutor(max_workers=20) as executor:
    for y in acls:
        executor.submit(convertToIP,y['srcSubnet'])

Тогда, если я попробую с concurrent.futures, обработайте его в 10-15 раз медленнее, и массив будет пустым. Код выглядит следующим образом:

aclsConverted = []
def convertToIP(ip):
    aclsConverted.append(ipaddress.ip_network(ip))

with concurrent.futures.ProcessPoolExecutor(max_workers=20) as executor:
    for y in acls:
        executor.submit(convertToIP,y['srcSubnet'])

Сервер, на котором я работаю, имеет 28 физических ядер.

Любые предложения о том, что я могу сделать неправильно, будут с благодарностью приняты!

Ответы [ 2 ]

0 голосов
/ 06 ноября 2019

Потоковый модуль предназначен для операций IN / OUT, он никак не может ускорить преобразование строк в экземпляр ip-адреса. Когда вы создаете потоки, вы тратите на них время, но не получаете никакого бонуса, поэтому программа без потоков работает быстрее.

Многопроцессорный модуль предназначен для тяжелых вычислений, таких как поиск суммы квадратов всех чисел в диапазоне от 0 до 1000 000 000 ... У вас операция не такая тяжелая. Многопроцессорному модулю необходимо сериализовать данные для отправки их от одного процесса к другому, поэтому это дорогостоящая операция, кроме того, порождение процессов также является дорогостоящим, в результате чего оно даже медленнее, чем потоковое в случае.

Я полагаю, чтоединственный способ ускорить выполнение программы - быстрее читать csv с помощью чего-то вроде панд, кроме того, вы можете затем преобразовать строку в ip внутри фрейма данных панд с помощью метода apply.

0 голосов
/ 06 ноября 2019

Если задачи слишком малы, то издержки на управление многопроцессорностью / многопоточностью зачастую дороже, чем преимущество параллельного выполнения задач.

Вы можете попробовать следующее:

Просто создатьдва процесса ( не потоки !!! ), один обрабатывает первые 5000 подсетей, другой - другие 5000 подсетей.

Там вы можете увидеть некоторое улучшение производительности. но задачи, которые вы выполняете, не слишком интенсивны для ЦП или ввода-вывода, поэтому не уверены, что они будут работать.

Многопоточность в Python, с другой стороны, не будет вообще никакого улучшения производительности для задач, чтоне имеют ввода-вывода, и это чистый код Python.

Причина в печально известном GIL (глобальная блокировка интерпретатора). В python вы никогда не сможете выполнять два байтовых кода python параллельно в одном и том же процессе.

Многопоточность в python все еще имеет смысл для задач, которые имеют IO (выполняющий доступ к сети), которые выполняют спящие процессы, которые вызывают модули, которыереализованы в C, и это действительно выпускает GIL. Например, numpy освобождает GIL и является хорошим кандидатом для многопоточности

...