Многопроцессорная обработка Python медленнее, чем одиночная
Sort.py
import random
import time
def time_analysis(func):
def do_func(*args, **kwargs):
print('[INFO] \'{}\' analysis started (N={}).'.format(func.__name__, len(args[0])))
start_time = time.clock()
result = func(*args, **kwargs)
end_time = time.clock()
total_time = end_time - start_time
print('[INFO] \'{}\' took {} seconds (N={}).'.format(func.__name__, total_time, len(args[0])))
return result
return do_func
@time_analysis
def bubble_sort(num_list):
num_len = len(num_list)
for i in range(num_len - 1):
for j in range(num_len - i - 1):
if num_list[j] > num_list[j + 1]:
num_list[j], num_list[j + 1] = num_list[j + 1], num_list[j]
return num_list
if __name__ == '__main__':
N = 30000
random_list = list(range(N))
random.shuffle(random_list)
bubble_sort(random_list)
random_list = list(range(N))
random.shuffle(random_list)
bubble_sort(random_list)
Parallel.py
from multiprocessing import Pool, cpu_count
from Sort import *
def bubble_sort_parallel(*args, **kwargs):
return bubble_sort(*args, **kwargs)
if __name__ == '__main__':
N = 30000
random_list = list(range(N))
random.shuffle(random_list)
pool.apply_async(bubble_sort_parallel, (random_list,))
random_list = list(range(N))
random.shuffle(random_list)
pool.apply_async(bubble_sort_parallel, (random_list,))
pool.close()
pool.join()
Один поток занял всего 2 секунды, но многопроцессорная обработка заняла 8 секунд.
N = 300 000 Один поток занял всего 200 секунд, а многопроцессорная обработка - 1400 секунд.
Почему многопроцессорная обработка медленнее, чем однопоточная?
Как я мог улучшить производительность?
Платформа: Linux, pypy2.7-5.10.0, 4 ядра на моем компьютере
Многопроцессорная обработка: [Рисунок многопроцессорной обработки][https://stackru.com/images/8b456fb279c63e8bc161631293b2a4ee641ab7b3.png]
Одна нить: [Рисунок одной нити][https://stackru.com/images/6b8bcb1191d9f478e361f34f5bb279cd87319f65.png]
2 ответа
Надеюсь, это уже было ясно Pool.apply_async
позволяет передавать работу другим процессам в пуле; он не распараллеливает автоматически одну функцию. Другими словами, обе версии выполняют каждую сортировку в одном потоке на одном ядре. Параллельная версия должна отправлять вызовы двух сортировок двум ядрам, но вы измеряете время выполнения каждого вида, а не выполнение всей программы, поэтому вы не обнаружите никакой экономии за счет перекрытия двух вызовов сортировки. (Кроме того, в настоящее время ваш код не включает создание объекта пула, поэтому я просто предполагаю, что вы использовали processes=N
для N > 2 - хотя, опять же, это не имеет значения, поскольку вы измеряете не общее время выполнения, а время выполнения каждого вида.)
(Если нет, см. https://docs.python.org/2/library/multiprocessing.html и https://docs.python.org/2/library/multiprocessing.html)
Это, однако, не объясняет, почему простая передача работы другому процессу приводит к более медленному времени выполнения. (Стоит отметить, что на моем MacBook Pro нет разницы во времени выполнения между простой версией и "параллельной" версией.) Причина медлительности - связь между процессами. Вы просите передать большой список через свой канал IPC, и это, очевидно, неэффективно. Вы можете продемонстрировать это сами: переместите создание списка и перетасовку в bubble_sort_parallel
и сделать аргумент для предоставленной функции в pool.apply_async
пустой список. На моем компьютере это делает среду выполнения идентичной базовой версии.
Я пробовал с N=15000
, На моем компьютере это работало практически одинаково, то есть непараллельная версия сортировала один массив за 26 секунд. и параллельная версия отсортировала два массива за 28 сек. Я поставил pool = Pool(2)
, Вы пытались увеличить N, возможно, ваши результаты будут сопоставимы для больших значений N в вашей среде.
ps Вы также должны иметь в виду, что процессы порождения также требуют ресурсов, и есть некоторые инструменты синхронизации.