Чому для багатопроцесорної обробки використовується лише одне ядро ​​після імпортування numpy?


127

Я не впевнений, чи сприймається це більше як проблема ОС, але я подумав, що запитую тут у випадку, якщо хтось матиме деяке розуміння з кінця речей 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час запуску цього сценарію:

htop

Я запускаю Ubuntu 12.10 (3.5.0-26) на ноутбуці з 4 ядрами. Зрозуміло, що joblib.Parallelце нерестування окремих процесів для різних працівників, але чи я можу змусити ці процеси виконуватись на різних ядрах?


stackoverflow.com/questions/15168014/… - відповіді там немає, я боюся, але це звучить як те саме питання.
NPE



Це все ще проблема? Я намагаюся відтворити це за допомогою Python 3.7 та імпортую numpy за допомогою багатопроцесорної обробки.Pool (), і він використовує всі потоки (як слід). Просто хочу переконатися, що це було виправлено.
Джаред Нільсен

Відповіді:


148

Після ще декількох гуглів я знайшов відповідь тут .

Виявляється, що деякі модулі Python ( numpy, scipy, tables, pandas, skimage...) зв'язуйтеся з основним спорідненістю з імпорту. Наскільки я можу сказати, ця проблема, здається, була викликана саме їх зв'язком з багатопотоковими бібліотеками OpenBLAS.

Вирішення завдання полягає в тому, щоб відновити спорідненість завдання за допомогою

os.system("taskset -p 0xff %d" % os.getpid())

Коли цей рядок вставлений після імпорту модуля, мій приклад тепер працює на всіх ядрах:

htop_workaround

До цього мого досвіду було те, що це, мабуть, не має негативного впливу на numpyефективність роботи, хоча це, мабуть, є специфічним для машин та завдань.

Оновлення:

Існує також два способи відключити поведінку, що скидає афінність процесора самого OpenBLAS. Наприклад, під час виконання можна використовувати змінну середовища OPENBLAS_MAIN_FREE(або GOTOBLAS_MAIN_FREE), наприклад

OPENBLAS_MAIN_FREE=1 python myscript.py

Або, якщо ви компілюєте OpenBLAS з джерела, ви можете остаточно відключити його під час збирання, відредагувавши Makefile.ruleрядок, що містить

NO_AFFINITY=1

Дякую, ваше рішення вирішило проблему. Одне запитання, у мене той самий код, але працює по-різному на буксирі різної машини. Обидві машини є Ubuntu 12.04 LTS, python 2.7, але ця проблема має лише одну. У вас є ідеї, чому?
iampat

На обох машинах є OpenBLAS (збірка з OpenMPI).
iampat

2
Стара тема, але якщо хтось інший знайде цю проблему, у мене виникла точна проблема, і вона справді була пов'язана з бібліотеками OpenBLAS. Дивіться тут два можливі шляхи вирішення та деякі пов'язані з цим дискусії.
Габріель

2
Ще один спосіб встановити спорідненість процесора - це використовуватиpsutil .
Іоанніс Filippidis

2
@JHG Це проблема з OpenBLAS, а не з Python, тому я не можу побачити жодної причини, чому версія Python
змінила

27

Тепер 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}

1
Помилка> AttributeError: у модуля 'os' немає атрибута 'sched_getaffinity', Python 3.6
Paddy

4
@Paddy Із пов'язаної документації: вони доступні лише на деяких платформах Unix.
BlackJack

2
У мене є така ж проблема, але я інтегрую цей самий рядок у верхній OS.system ("набір завдань -p 0xff% d"% os.getpid ()), але він використовує не всі процесори
rajeshcis

12

Це, як видається, є частою проблемою з Python в Ubuntu, і не характерно для joblib:

Я б запропонував експериментувати з спорідненістю процесора ( taskset).


Python on UbuntuЦе означає, що він працює без проблем в Windows та інших ОС. Є це?
щогли
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.