Многопроцессорность python: нет уменьшающихся результатов?
Скажем, я хочу парализовать некоторые интенсивные вычисления (не связанные с I/O).
Естественно, я не хочу запускать больше процессов, чем доступные процессоры, или я бы начал платить за переключение контекста (и промахи кэша).
Ментально, я ожидал бы, что при увеличении n
в multiprocessing.Pool(n)
общее время будет вести себя следующим образом:
![mockup]()
- отрицательный наклон, поскольку задачи используют преимущества распараллеливания
- положительный наклон, так как переключение контекста начинает меня стоить
- плато
Но на самом деле я получаю это:
![real]()
#!/usr/bin/env python
from math import factorial
def pi(n):
t = 0
pi = 0
deno = 0
k = 0
for k in range(n):
t = ((-1)**k)*(factorial(6*k))*(13591409+545140134*k)
deno = factorial(3*k)*(factorial(k)**3)*(640320**(3*k))
pi += t/deno
pi = pi * 12/(640320**(1.5))
pi = 1/pi
return pi
import multiprocessing
import time
maxx = 20
tasks = 60
task_complexity = 500
x = range(1, maxx+1)
y = [0]*maxx
for i in x:
p = multiprocessing.Pool(i)
tic = time.time()
p.map(pi, [task_complexity]*tasks)
toc = time.time()
y[i-1] = toc-tic
print '%2d %ds' % (i, y[i-1])
import matplotlib.pyplot as plot
plot.plot(x, y)
plot.xlabel('Number of threads')
plot.xlim(1, maxx)
plot.xticks(x)
plot.ylabel('Time in seconds')
plot.show()
Моя машина: i3-3217U CPU @1.80GHz × 4
Операционная система: Ubuntu 14.04
После n > 4 я вижу, что диспетчер задач вращается через различные процессы, как и ожидалось, поскольку процессов больше, чем процессоров. Тем не менее, нет никакого штрафа относительно n = 4 (мое число процессоров).
Фактически, даже когда n < 4, я вижу, что планировщик фанетически поворачивает процессы через мои процессоры, вместо того, чтобы назначать каждый процесс его собственному процессору и избегать переключения контекста.
Я наблюдаю это поведение с помощью gnome-system-monitor: (Пожалуйста, дайте мне знать, если у кого-то есть другой опыт.)
![gnome-system-monitor]()
Любое объяснение, почему, похоже, не важно, сколько процессов я запускаю? Или что-то не так с моим кодом?
Мое предположение: похоже, что процессы не связаны с процессором (даже когда активны только два процесса, они продолжают переключать CPU), и поэтому я плачу за переключение контекста.
Литература:
EDIT: обновленная графика и код с более высокими константами.
Ответы
Ответ 1
Фактически, даже когда n < 4, я вижу, что планировщик frenetically вращает процессов через мои процессоры, вместо того, чтобы присваивать каждому процессу его собственный процессор и избежать переключения контекста.
Процессы по умолчанию не ограничены процессором, одна из основных причин заключается в том, чтобы избежать неодинакового нагрева процессора, что может вызвать механическое напряжение и сократить срок его службы.
Существуют способы принудительного запуска процесса на одном ядре (смотрите модуль psutil
), который имеет такие преимущества, как лучшее использование кеш-памяти и исключение переключения контекста, но в большинстве случаев (если не все) вы не имеют большого значения с точки зрения выступлений.
Итак, если вы создаете больше процессов, чем количество ядер, они будут действовать как потоки и переключаться между ними для оптимизации выполнения. Производительность процессора будет немного (очень) немного понижена, так как вы уже переключали контекст с менее чем 4 процессами.
Ответ 2
Отвечая на мой собственный вопрос:
Во-первых, я, кажется, допустил ошибку в своем сообщении. Не похоже, чтобы используемый CPU менялся отчаянно. Если я запускаю два процессора с интенсивным процессом, они меняют ядра, но только между двумя ядрами. Мой компьютер имеет 4 ядра, каждый из которых имеет 2 "мягких" ядра (для гиперпотока). Я предполагаю, что происходит, что он меняется между этими двумя "мягкими" ядрами. Это не Linux, это процессорная плата.
Это, как говорится, я все еще удивляюсь, что переключение контекста не больнее, чем оно есть.
РЕДАКТИРОВАТЬ: Хорошая дискуссия с лучшей эмпирической работой, чем я, над этот блог. p >