Несколько слов о multiprocessing Pool
дата публикации: 2016-02-12В первое время python был для меня языком для решения математических задач, построения алгоритмов и т.д. На тот момент я не задумывался о применении этого языка в задачах web программирования и спокойно писал на php, вообще не задумывался о "фишках", которые позволяют использовать преимущества конкретного языка. Однако рано или поздно каждый программист мыслит о построении кода, который не просто работает, а работает оптимально по тем или иным критериям. Если говорить о времени работы программы, то тут обязательно нужно знать подходы к распараллеливанию кода.
Вообще, python в этом отношении имеет ряд проблем, которые связаны по большей степени с Global Interpreter Lock (GIL), работа которого заложена в идеологию python. Не хочу вдаваться в подробности вопроса надобности такого замка, не буду рассказывать обходные пути, а просто покажу пример оптимизации работы программы по критерию быстродействия с помощью модуля multiprocessing
# подключение библиотек from multiprocessing import Pool, cpu_count import time # описание функции, выполняющей роль нагрузки def loadFunction(n) : i = 0 while i < n : i += 1 #начало программы if __name__ == '__main__' : k = 20 n = 10000000 s = 1 clc = time.time() if s == 0 : for i in range(k) : loadFunction(n) elif s == 1 : pool = Pool(cpu_count()) arg = [] for i in range(k) : arg.append(n) pool.map(loadFunction, arg) clc = time.time() - clc print('время {0:.2f} секунд'.format(clc)) input()
В представленном вашему вниманию коде реализовано два варианта развития событий, первый - расчет функции нагрузки в одном процессе, во втором случае число процессов равно количеству ядер процессора, в моем случае 2 ядра. Полученные результаты работы программы: без использования мультипроцессов (s = 0) 20.97 секунд на работу программы, с использованием мультипроцессов (s = 1) 16.31, что более чем на 20% быстрее. Приведу графики загрузки процессора и количества процессов

Первый график показывает, что программа не загружала второе ядро, а только одно и то не на 100%, в памяти "висел" один процесс (второй это IDLE), а вот во втором случае загрузка обеих ядер была 100% при этом было запущено три процесса (один родительский и два дочерних) в памяти.
В качестве вывода хочу сказать, что распараллеливание следует применять там, где оно действительно необходимо, так как дополнительный процесс в памяти как минимум требует время на запуск. В этой короткой статье не рассматриваю вопрос создания потоков, ввиду того, что без "костылей" не имеет смысла реализовывать их в python.