Я экспериментирую с многопроцессорным модулем Python 3 и имею следующий код, который читает файл, содержащий число в каждой строке, и печатает факторизацию каждого числа:
import multiprocessing
import sys
NUM_PROCESSES = 4
CHUNK_SIZE = 20
def factor(n):
#Return a list of factors of n
factors = []
#factor out 2's
while n % 2 == 0:
factors.append(2)
n //= 2
factor = 3
while n > 1:
if n % factor == 0:
factors.append(factor)
n //= factor
else:
factor += 2
return factors
def process_line(line):
#process an input file line
number = int(line)
factorization = '*'.join(str(x) for x in factor(number))
return f'{number} = {factorization}\n'
if __name__ == '__main__':
with open('input.txt') as f:
with multiprocessing.Pool(NUM_PROCESSES) as pool:
processed = pool.imap(process_line, f, CHUNK_SIZE)
sys.stdout.writelines(processed)
Я запускаю это в системе Linux с 2 физическими ядрами с гиперпоточностью, всего 4 виртуальных ядра. Я протестировал этот сценарий на файле, содержащем 10 000 случайных чисел от 2 до 1 000 000, и измерил его производительность с помощью команды time
.
Когда NUM_PROCESSES
равно 1, я получаю результат:
real 0m26.997s
user 0m26.979s
sys 0m0.077s
Когда NUM_PROCESSES
равно 2, я получаю:
real 0m13.477s
user 0m26.809s
sys 0m0.048s
Пока это то, что я ожидал - добавление еще одного процесса сокращает время выполнения почти вдвое, в то время как общее время процессора остается прежним. Но когда NUM_PROCESSES
равно 4, я получаю:
real 0m14.598s
user 0m56.703s
sys 0m0.059s
Время выполнения не только не уменьшилось, но и увеличилось на 1 секунду, хотя время процессора увеличилось вдвое. По сути, это означает, что каждый виртуальный ЦП работал на половине скорости физического ЦП, поэтому от работы на всех 4 виртуальных ЦП не было никакого выигрыша в производительности. Изменение CHUNK_SIZE
, по-видимому, не оказывает существенного влияния на производительность, даже если я установил его на 1 или 2500. Использование map()
вместо imap()
также ничего не меняет.
Насколько я понимаю, виртуальные ядра с поддержкой Hyper-Threading не дают таких же преимуществ в производительности, как дополнительные физические ядра, но они все же должны давать некоторое улучшение, верно? Почему тогда производительность скрипта не улучшилась?