Как ограничить количество процессоров, используемых скриптом Python без терминала или многопроцессорной библиотеки?

1

Моя главная проблема оформлена здесь. Поскольку никто еще не дал решения, я решил найти обходной путь. Я ищу способ ограничить использование процессора скриптами Python (не приоритет, но количество ядер процессора) с помощью кода Python. Я знаю, что могу сделать это с многопроцессорной библиотекой (пул и т.д.), Но я не тот, кто запускает ее с многопроцессорной обработкой. Итак, я не знаю, как это сделать. И также я мог бы сделать это через терминал, но этот скрипт импортируется другим скриптом. К сожалению, я не могу позволить себе звонить через терминал.

tl; dr: Как ограничить использование процессора (количество ядер) скрипта Python, который импортируется другим скриптом, и я даже не знаю, почему он работает параллельно, без запуска через терминал. (Пожалуйста, проверьте фрагмент кода ниже, и да, английский не мой родной язык)

Фрагмент кода, вызывающий проблему:

from sklearn.datasets import load_digits
from sklearn.decomposition import IncrementalPCA
import numpy as np

X, _ = load_digits(return_X_y=True)

#Copy-paste and increase the size of the dataset to see the behavior at htop.
for _ in range(8):
    X = np.vstack((X, X))

print(X.shape)

transformer = IncrementalPCA(n_components=7, batch_size=200)

#PARTIAL FIT RUNS IN PARALLEL! GOD WHY?
---------------------------------------
transformer.partial_fit(X[:100, :])
---------------------------------------
X_transformed = transformer.fit_transform(X)

print(X_transformed.shape)

Версии:

  • Python 3.6
  • Joblib 0.13.2
  • scikit-learn 0.20.2
  • numpy 1.16.2

ОБНОВЛЕНИЕ: не работает. Спасибо за разъяснения @Darkonaut. Печально то, что я уже знал, что это не сработает, и я уже четко указал название вопроса, но люди не читают, я думаю. Я думаю, я делаю это неправильно. Я обновил фрагмент кода на основе @Ben Chaliah Аюба ответ. Кажется, ничего не изменилось. И еще я хочу указать на кое-что: я не пытаюсь запустить этот код на нескольких ядрах. Эта строка transformer.partial_fit(X[:100, :]) n_jobs transformer.partial_fit(X[:100, :]) работает на нескольких ядрах (по некоторым причинам) и не имеет n_jobs или чего-либо еще. Также обратите внимание, что мой первый пример и мой оригинальный код не инициализированы с пулом или чем-то подобным. Я не могу установить количество ядер в первую очередь (потому что такого места нет). Но теперь есть место для этого, но он все еще работает на нескольких ядрах. Не стесняйтесь проверить это самостоятельно. (Код ниже) Вот почему я ищу обходной путь.

from sklearn.datasets import load_digits
from sklearn.decomposition import IncrementalPCA
import numpy as np
from multiprocessing import Pool, cpu_count
def run_this():
    X, _ = load_digits(return_X_y=True)
    #Copy-paste and increase the size of the dataset to see the behavior at htop.
    for _ in range(8):
        X = np.vstack((X, X))
    print(X.shape)
    #This is the exact same example taken from sckitlearn IncrementalPCA website.
    transformer = IncrementalPCA(n_components=7, batch_size=200)
    transformer.partial_fit(X[:100, :])
    X_transformed = transformer.fit_transform(X)
    print(X_transformed.shape)
pool= Pool(processes=1)
pool.apply(run_this)

ОБНОВЛЕНИЕ: Итак, я попытался установить потоки Blas, используя это в моем коде, прежде чем импортировать Numpy, но это не сработало (снова). Любые другие предложения? Последний этап кода можно найти ниже.

Кредиты: @Amir

from sklearn.datasets import load_digits
from sklearn.decomposition import IncrementalPCA
import os
os.environ["OMP_NUM_THREADS"] = "1" # export OMP_NUM_THREADS=1
os.environ["OPENBLAS_NUM_THREADS"] = "1" # export OPENBLAS_NUM_THREADS=1
os.environ["MKL_NUM_THREADS"] = "1" # export MKL_NUM_THREADS=1
os.environ["VECLIB_MAXIMUM_THREADS"] = "1" # export VECLIB_MAXIMUM_THREADS=1
os.environ["NUMEXPR_NUM_THREADS"] = "1" # export NUMEXPR_NUM_THREADS=1

import numpy as np

X, _ = load_digits(return_X_y=True)

#Copy-paste and increase the size of the dataset to see the behavior at htop.
for _ in range(8):
    X = np.vstack((X, X))

print(X.shape)
transformer = IncrementalPCA(n_components=7, batch_size=200)

transformer.partial_fit(X[:100, :])

X_transformed = transformer.fit_transform(X)

print(X_transformed.shape)
  • 0
    Вы не можете решить эту проблему, запустив программу с помощью nice ? Я так понимаю, это то, что вы действительно хотите?
  • 0
    не nice менять приоритет работы? Я ищу способ изменить количество ядер процессора.
Показать ещё 8 комментариев
Теги:
python-3.x
multiprocessing
python-multiprocessing

3 ответа

5

если вы хотите ограничить количество используемых ядер, то вы используете multiprocessing.Pool который создает пул рабочих процессов на основе максимального количества ядер, доступных в вашей системе, а затем в основном передает задачи по мере того, как ядра становятся доступными:

pool= Pool(processes=(multiprocessing.cpu_count() - 1))

Также неплохим хороший подход для уменьшения приоритета процесса:

from multiprocessing import Pool, cpu_count
import math, os, psutil, platform


def foo(x):
    return math.cos(x)

def limit_cpu():
    p = psutil.Process(os.getpid())
    if platform.system() == 'Linux':
        p.nice(19)
    elif platform.system() == 'Windows':
        p.nice(psutil.BELOW_NORMAL_PRIORITY_CLASS)


if __name__ == '__main__':
    pool = Pool(None, limit_cpu)
    for p in pool.imap(foo, range(10**8)):
        pass

Если вы хотите, чтобы процесс не занимал 100% ядра:

from time import sleep
def foo(x):
    sleep(0.01)
    return math.sqrt(x)

Это позволит вашей операционной системе schedule out процесс на 0.01 секунды для каждого вычисления и освобождает место для других приложений.

Вы можете запустить свой PCA внутри foo

1

Я решил проблему в примере кода, приведенном в исходном вопросе, установив переменные среды BLAS (по этой ссылке). Но это не ответ на мой актуальный вопрос. Моя первая попытка (второе обновление) была неправильной. Мне нужно было установить количество потоков не перед импортом библиотеки NUMPY, а до импорта библиотеки NUMPY (IncrementalPCA).
Итак, в чем была проблема в примере кода? Это была не проблема, а особенность библиотеки BLAS, используемой библиотекой numpy. Попытка ограничить его с помощью многопроцессорной библиотеки не сработала, потому что по умолчанию OpenBLAS настроен на использование всех доступных потоков.
Кредиты: @Amir и @Darkonaut. Источники: OpenBLAS 1, OpenBLAS 2, решение.

import os
os.environ["OMP_NUM_THREADS"] = "1" # export OMP_NUM_THREADS=1
os.environ["OPENBLAS_NUM_THREADS"] = "1" # export OPENBLAS_NUM_THREADS=1
os.environ["MKL_NUM_THREADS"] = "1" # export MKL_NUM_THREADS=1
os.environ["VECLIB_MAXIMUM_THREADS"] = "1" # export VECLIB_MAXIMUM_THREADS=1
os.environ["NUMEXPR_NUM_THREADS"] = "1" # export NUMEXPR_NUM_THREADS=1
from sklearn.datasets import load_digits
from sklearn.decomposition import IncrementalPCA


import numpy as np

X, _ = load_digits(return_X_y=True)

#Copy-paste and increase the size of the dataset to see the behavior at htop.
for _ in range(8):
    X = np.vstack((X, X))

print(X.shape)
transformer = IncrementalPCA(n_components=7, batch_size=200)

transformer.partial_fit(X[:100, :])

X_transformed = transformer.fit_transform(X)

print(X_transformed.shape)

Но вы можете явно установить правильную среду BLAS, проверив, какая из них используется вашей numpy сборкой, например:

>>>import numpy as np
>>>np.__config__.show()

** дал эти результаты... **

blas_mkl_info:
  NOT AVAILABLE
blis_info:
  NOT AVAILABLE
openblas_info:
    libraries = ['openblas', 'openblas']
    library_dirs = ['/usr/local/lib']
    language = c
    define_macros = [('HAVE_CBLAS', None)]
blas_opt_info:
    libraries = ['openblas', 'openblas']
    library_dirs = ['/usr/local/lib']
    language = c
    define_macros = [('HAVE_CBLAS', None)]
lapack_mkl_info:
  NOT AVAILABLE
openblas_lapack_info:
    libraries = ['openblas', 'openblas']
    library_dirs = ['/usr/local/lib']
    language = c
    define_macros = [('HAVE_CBLAS', None)]
lapack_opt_info:
    libraries = ['openblas', 'openblas']
    library_dirs = ['/usr/local/lib']
    language = c
    define_macros = [('HAVE_CBLAS', None)]

... то есть OpenBLAS используется моей сборкой. И все, что мне нужно написать, это os.environ["OPENBLAS_NUM_THREADS"] = "2" , чтобы ограничить использование потоков библиотекой numpy.

0

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

Запустите ваше приложение с taskset. Например, чтобы ограничить количество используемых процессоров до 4, выполните:

taskset --cpu-list 0,1,2,3 <app>
  • 0
    это команда терминала?
  • 0
    @MehmedB Это приложение командной строки, оно может работать в терминале.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню