модуль многопроцессорности python: странное поведение и загрузка процессора при использовании пула

Я использую многопроцессорную библиотеку Python, чтобы ускорить некоторый код (метод наименьших квадратов, соответствующий scipy).

Он отлично работает на 3-х разных машинах, но показывает странное поведение на 4-й машине.

Код:

import numpy as np
from scipy.optimize import least_squares
import time
import parmap
from multiprocessing import Pool

p0 = [1., 1., 0.5]

def f(p, xx):
    return p[0]*np.exp(-xx ** 2 / p[1] ** 2) + p[2]

def errorfunc(p, xx, yy):
    return f(p, xx) - yy

def do_fit(yy, xx):
    return least_squares(errorfunc, p0[:], args=(xx, yy))

if __name__ == '__main__':
    # create data
    x = np.linspace(-10, 10, 1000)
    y = []
    np.random.seed(42)
    for i in range(1000):
        y.append(f([np.random.rand(1) * 10, np.random.rand(1), 0.], x) + np.random.rand(len(x)))

    # fit without multiprocessing
    t1 = time.time()
    for y_data in y:
        p1 = least_squares(errorfunc, p0[:], args=(x, y_data))
    t2 = time.time()
    print t2 - t1

    # fit with multiprocessing lib
    times = []
    for p in range(1,13):
        my_pool = Pool(p)
        t3 = time.time()
        results = parmap.map(do_fit, y, x, pool=my_pool)
        t4 = time.time()
        times.append(t4-t3)
        my_pool.close()
    print times

Для 3 машин, на которых он работает, он ускоряется примерно ожидаемым образом. Например. на моем ноутбуке i7 это дает:

[4.92650294303894, 2.5883090496063232, 1.7945551872253418, 1.629533052444458, 
1.4896039962768555, 1.3550388813018799, 1.1796400547027588, 1.1852478981018066, 
1.1404039859771729, 1.2239141464233398, 1.1676840782165527, 1.1416618824005127]

Я использую Ubuntu 14.10, Python 2.7.6, numpy 1.11.0 и scipy 0.17.0. Я протестировал его на другом компьютере с Ubuntu, Dell PowerEdge R210 с аналогичными результатами и на MacBook Pro Retina (здесь с Python 2.7.11 и теми же версиями numpy и scipy).

Компьютер, который вызывает проблемы, — это PowerEdge R710 (два шестнадцатеричных ядра), работающий под управлением Ubuntu 15.10, Python 2.7.11 и той же версии numpy и scipy, что и выше. Однако никакого ускорения я не наблюдаю. Время составляет около 6 секунд, независимо от того, какой размер пула я использую. Фактически, это немного лучше для размера пула, равного 2, и ухудшается для большего количества процессов.

htop показывает, что каким-то образом создается больше процессов, чем я ожидал.

Например. на моем ноутбуке htop показывает одну запись для каждого процесса (что соответствует размеру пула), и в конечном итоге каждый процесс показывает 100% загрузку ЦП.

На PowerEdge R710 я вижу около 8 процессов Python для размера пула 1 и около 20 процессов для размера пула 2 и т. д., каждый из которых показывает 100% загрузку ЦП.

Я проверил настройки BIOS R710 и не нашел ничего необычного. Что я должен искать?

РЕДАКТИРОВАТЬ: отвечая на комментарий, я использовал другой простой скрипт. Удивительно, но этот, кажется, «работает» для всех машин:

from multiprocessing import Pool
import time
import math
import numpy as np

def f_np(x):
    return x**np.sin(x)+np.fabs(np.cos(x))**np.arctan(x)

def f(x):
    return x**math.sin(x)+math.fabs(math.cos(x))**math.atan(x)

if __name__ == '__main__':
    print "#pool", ", numpy", ", pure python"
    for p in range(1,9):
        pool = Pool(processes=p)
        np.random.seed(42)
        a = np.random.rand(1000,1000)
        t1 = time.time()
        for i in range(5):
            pool.map(f_np, a)
        t2 = time.time()
        for i in range(5):
            pool.map(f, range(1000000))
        print p, t2-t1, time.time()-t2
        pool.close()

дает:

#pool , numpy , pure python
1 1.34186911583 5.87641906738
2 0.697530984879 3.16030216217
3 0.470160961151 2.20742988586
4 0.35701417923 1.73128080368
5 0.308979988098 1.47339701653
6 0.286448001862 1.37223601341
7 0.274246931076 1.27663207054
8 0.245123147964 1.24748778343

на машине, вызвавшей проблему. Создано не больше потоков (или процессов?), чем я ожидал.

Похоже, проблема не в numpy, но как только я использую scipy.optimize.least_squares, возникает проблема.

Использование htop в процессах показывает много вызовов sched_yield(), которые я не вижу, если не использую scipy.optimize.least_squares, и которые я также не вижу на своем ноутбуке, даже когда использую least_squares.


person Julian S.    schedule 18.04.2016    source источник
comment
Поскольку вы используете htop, попробуйте выбрать каждый из 8 процессов Python на неисправной машине и нажать s для strace. Посмотрите, что каждый процесс делает с этими 100% процессорного времени. Кроме того, попробуйте более простую тестовую программу, которая вообще не использует Numpy.   -  person John Zwinck    schedule 19.04.2016
comment
Я отредактировал свой оригинальный пост. Я использовал более сложный пример в первую очередь потому, что он ближе к моей последней проблеме.   -  person Julian S.    schedule 20.04.2016
comment
Давайте попробуем выяснить, где порождаются эти процессы, не так ли? Вы можете запустить свою программу под отладчиком, например. gdb --args python yourscript.py... затем break fork, чтобы остановиться при создании нового процесса, а затем посмотреть, что делает разветвление. Это могут быть базовые подпрограммы C или Fortran внутри Scipy. См. sourceware.org/gdb/onlinedocs/gdb/Forks.html.   -  person John Zwinck    schedule 20.04.2016


Ответы (1)


Согласно здесь, возникает проблема при использовании OpenBLAS вместе с joblib .

Аналогичные проблемы возникают при использовании MKL (см. здесь). Решение, данное здесь, также сработало для меня: добавление

import os
os.environ['MKL_NUM_THREADS'] = '1'

в начале моего скрипта Python решает проблему.

person Julian S.    schedule 21.04.2016