Почему мультипроцессор использует только одно ядро после импорта numpy?
Я не уверен, считается ли это больше проблемой ОС, но я подумал, что могу спросить здесь, если у кого-то есть понимание с конца Python.
Я пытался распараллелить процессор for
использование цикла joblib
, но я нахожу, что вместо того, чтобы каждый рабочий процесс был назначен на другое ядро, я получаю, что все они назначены на одно и то же ядро, а производительность не увеличивается.
Вот очень тривиальный пример...
from joblib import Parallel,delayed
import numpy as np
def testfunc(data):
# some very boneheaded CPU work
for nn in xrange(1000):
for ii in data[0,:]:
for jj in data[1,:]:
ii*jj
def run(niter=10):
data = (np.random.randn(2,100) for ii in xrange(niter))
pool = Parallel(n_jobs=-1,verbose=1,pre_dispatch='all')
results = pool(delayed(testfunc)(dd) for dd in data)
if __name__ == '__main__':
run()
... и вот что я вижу в htop
пока этот скрипт работает:
Я использую Ubuntu 12.10 (3.5.0-26) на ноутбуке с 4 ядрами. очевидно joblib.Parallel
порождает ли отдельные процессы для разных работников, но есть ли способ заставить эти процессы выполняться на разных ядрах?
3 ответа
После еще нескольких поисков я нашел ответ здесь.
Оказывается, что некоторые модули Python (numpy
, scipy
, tables
, pandas
, skimage
...) беспорядок с основной привязкой при импорте. Насколько я могу судить, эта проблема, по-видимому, вызвана тем, что они связаны с многопоточными библиотеками OpenBLAS.
Обходной путь - сбросить сходство задачи, используя
os.system("taskset -p 0xff %d" % os.getpid())
С этой строкой, вставленной после импорта модуля, мой пример теперь работает на всех ядрах:
Мой опыт показывает, что это никак не влияет на numpy
производительность, хотя это, вероятно, зависит от машины и задачи.
Обновить:
Есть также два способа отключить поведение сброса соответствия процессоров самого OpenBLAS. Во время выполнения вы можете использовать переменную окружения OPENBLAS_MAIN_FREE
(или же GOTOBLAS_MAIN_FREE
), например
OPENBLAS_MAIN_FREE=1 python myscript.py
Или же, если вы компилируете OpenBLAS из исходного кода, вы можете навсегда отключить его во время сборки, отредактировав Makefile.rule
содержать строку
NO_AFFINITY=1
Python 3 теперь предоставляет методы для прямой установки сродства
>>> import os
>>> os.sched_getaffinity(0)
{0, 1, 2, 3}
>>> os.sched_setaffinity(0, {1, 3})
>>> os.sched_getaffinity(0)
{1, 3}
>>> x = {i for i in range(10)}
>>> x
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
>>> os.sched_setaffinity(0, x)
>>> os.sched_getaffinity(0)
{0, 1, 2, 3}
Это похоже на общую проблему с Python в Ubuntu и не относится к joblib
:
- И multiprocessing.map, и joblib используют только 1 процессор после обновления с Ubuntu 10.10 до 12.04
- Многопроцессорная обработка Python использует только одно ядро
- multiprocessing.Pool процессы привязаны к одному ядру
Я бы предложил поэкспериментировать с привязкой к процессору (taskset
).