【问题标题】:How to limit number of CPU's used by a python script w/o terminal or multiprocessing library?如何限制没有终端或多处理库的python脚本使用的CPU数量?
【发布时间】:2019-04-18 13:16:59
【问题描述】:

我的主要问题是here。由于还没有人给出解决方案,我决定找到一种解决方法。我正在寻找一种方法来使用 python 代码限制 python 脚本 CPU 使用率(不是优先级,而是 CPU 内核的数量)。我知道我可以使用多处理库(池等)来做到这一点,但我不是使用多处理运行它的人。所以,我不知道该怎么做。我也可以通过终端执行此操作,但此脚本正在由另一个脚本导入。不幸的是,我没有通过终端调用它的奢侈。

tl;dr:如何限制 python 脚本的 CPU 使用率(核心数),该脚本正在由另一个脚本导入,我什至不知道它为什么并行运行,没有通过终端运行它。请检查下面的代码sn-p。

导致问题的代码sn-p:

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 Ayoub answer 更新了代码 sn-p。似乎什么都没有改变。而且我还想指出一点:我不想在多个内核上运行这段代码。这条线 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's 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)

更新:因此,我尝试在导入 numpy 之前在我的代码中使用 this 设置 blas 线程,但它(再次)不起作用。还有其他建议吗?最新阶段的代码可以在下面找到。

致谢: @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)

【问题讨论】:

  • 你不能用nice 运行程序来解决这个问题吗?我猜这才是你真正想要的?
  • nice 不是关于更改工作的优先级吗?我正在寻找一种方法来更改 CPU 内核的数量。
  • Pool 在这里帮不了你。 sklearn 建立在 numpy 之上,GIL-通过其数学库释放多线程。 Pool 的processes-参数仅控制创建了多少工作进程,它不会对您的函数执行任何核心使用限制。您需要限制的是numpy 使用的线程数。
  • 如果您的 numpy-build 在后台使用 MKL,您的解决方案可以像添加 import mkl; mkl.set_num_threads(1) 一样简单。查找更多答案 herehere
  • 这不是错误,而是缺少的功能。对于通常的用例,您会很高兴克服 GIL 的限制并免费拥有真正并行的 numpy 多线程。但是那个 numpy 没有公开一个高级 API 来打开/关闭多线程确实是不幸的(参见github 的讨论)。可能对OpenBlas有帮助。

标签: python python-3.x unix multiprocessing python-multiprocessing


【解决方案1】:

我正在寻找一种方法来限制 python 脚本的 CPU 使用率(不是优先级,而是 CPU 内核的数量)。

使用tasksetnumactl 运行您的应用程序。

例如,让您的应用程序仅使用前 4 个 CPU:

taskset --cpu-list 0-3 <app>

但是,这些工具将进程限制为使用特定的 CPU,而不是使用的 CPU 总数。为了获得最佳结果,他们需要将这些 CPU 与 OS 进程调度程序隔离,以便调度程序不会在这些 CPU 上运行任何其他进程。否则,如果指定的 CPU 当前正在运行其他线程,而其他 CPU 处于空闲状态,则您的线程将无法在其他空闲 CPU 上运行,并且必须为这些特定 CPU 排队,这并不理想。

使用cgroups,您可以限制您的进程/线程使用特定部分的可用CPU 资源,而不限制特定的CPU,但cgroups 设置不那么简单。

【讨论】:

    【解决方案2】:

    我通过设置 BLAS 环境变量(来自this 链接)解决了原始问题中给出的示例代码中的问题。 但这不是我实际问题的答案。我的第一次尝试(第二次更新)是错误的。我需要设置线程数不是在导入 numpy 库之前,而是在库 (IncrementalPCA) 导入 numpy 之前
    那么,示例代码中的问题是什么?这不是一个实际问题,而是 numpy 库使用的 BLAS 库的一个特性。尝试使用多处理库来限制它不起作用,因为默认情况下 OpenBLAS 设置为使用所有可用线程。
    致谢:@Amir 和 @Darkonaut 来源OpenBLAS 1OpenBLAS 2Solution

    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)]
    

    ...意思是我的 numpy 构建使用了 OpenBLAS。我只需要写os.environ["OPENBLAS_NUM_THREADS"] = "2" 来限制numpy 库的线程使用。

    【讨论】:

      猜你喜欢
      • 2014-12-25
      • 2022-08-15
      • 1970-01-01
      • 2020-12-02
      • 2020-05-20
      • 1970-01-01
      • 2012-06-18
      • 2015-09-10
      • 2014-06-07
      相关资源
      最近更新 更多