在我的两台计算机上,我尝试了以下代码:

N <- 10e3
M <- 2000
X <- matrix(rnorm(N * M), N)
system.time(crossprod(X))

第一个是标准笔记本电脑,此操作需要 1.7 秒。
> sessionInfo()
R version 3.4.4 (2018-03-15)
Platform: x86_64-redhat-linux-gnu (64-bit)
Running under: CentOS Linux 7 (Core)

Matrix products: default
BLAS/LAPACK: /usr/lib64/R/lib/libRblas.so

第二个是相当不错的台式电脑,花了 17 秒。
> sessionInfo()
R version 3.4.4 (2018-03-15)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Linux Mint 18.3

Matrix products: default
BLAS: /usr/lib/libblas/libblas.so.3.6.0
LAPACK: /usr/lib/lapack/liblapack.so.3.6.0

台式计算机的性能比膝上型计算机要高,但这种矩阵计算需要 10 倍的时间。

问题是否来自使用的默认 BLAS/LAPACK?

最佳答案

tldr: CentOS 使用单线程 OpenBLAS,Linux Mint 默认使用 Reference BLAS,但可以使用其他 BLAS 版本。

EPEL 提供的 CentOS 的 R 包依赖于 openblas-Rblas 。这似乎是一个为 R 提供 BLAS 的 OpenBLAS 版本。所以虽然看起来使用了 R 的 BLAS,但它实际上是 OpenBLAS。 LAPACK 版本始终是 R 提供的版本。

在 Debian 和 Mint 等衍生发行版上,r-base-core 取决于

  • libblas3 | libblas.so.3
  • liblapack3 | liblapack.so.3

  • 默认情况下,这些由引用实现 libblas3liblapack3 提供。这些不是特别快,但您可以通过安装 libopenblas-base 之类的软件包轻松替换它们。您可以通过 update-alternatives 控制系统上使用的 BLAS 和 LAPACK。

    为了使用 OpenBLAS 控制线程数,我通常使用 RhpcBLASctl :
    N <- 20000
    M <- 2000
    X <- matrix(rnorm(N * M), N)
    RhpcBLASctl::blas_set_num_threads(2)
    system.time(crossprod(X))
    #>        User      System verstrichen
    #>       2.492       0.331       1.339
    RhpcBLASctl::blas_set_num_threads(1)
    system.time(crossprod(X))
    #>        User      System verstrichen
    #>       2.319       0.052       2.316
    

    由于某种原因,从 R 设置 environment variables OPENBLAS_NUM_THREADSGOTO_NUM_THREADSOMP_NUM_THREADS 并没有达到预期的效果。在 CentOS 上,甚至 RhpcBLASctl 也无济于事,因为使用的 OpenBLAS 是单线程的。

    关于r - 用于矩阵计算的操作系统之间的巨大性能差异,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55615428/

    10-10 13:07