【问题标题】:One liner for n-1 cores?n-1 个内核的一个衬垫?
【发布时间】:2017-03-17 16:24:50
【问题描述】:

使用标志 -j 运行 make 会使用所有可用的内核,但这有时会导致线程崩溃或发生其他坏事。

在 bash 脚本中,我如何使用 n-1 内核代替(仅当 n>1 否则为 1)。

一定有比这更简单的方法:

NJOBS=$((`getconf _NPROCESSORS_ONLN 2>/dev/null \
   || sysctl hw.ncpu  \
   || echo 2` \
   - 1))

【问题讨论】:

  • 顺便说一下,NJOBS 全部大写并不是一种好的形式——参见POSIX Issue 7 spec on environment variables,它指定全大写名称用于对操作系统和有意义的变量shell,并且保留至少一个小写字符的名称供应用程序使用。由于设置 shell 变量将覆盖任何类似命名的环境变量,因此该约定也适用于此。
  • 即使您的不那么简单的解决方案也无法处理 n = 1 案例,还是我遗漏了什么?

标签: bash math makefile jobs


【解决方案1】:

您当前的代码不简单的全部原因是它试图执行一个没有跨多个操作系统的标准化接口的操作。因此,为了尽可能多地获得适用于当前操作系统的方法,它会经历多种可能性:

  • getconf _NPROCESSORS_ONLN 适用于 Linux 和 MacOS X,但不适用于 Solaris、FreeBSD、NetBSD 等。
  • sysctl hw.ncpu 适用于大多数非 Solaris 系统。
  • 2 是一个安全的默认值,因为减去 1 将只返回一个内核的值。

要在 Solaris 上工作,需要将 psrinfo -p 添加到可能的备用列表中,从而使您的代码更加冗长。


如果您愿意在可移植性方面做出一些妥协(但仍保留最后的回退,以便在 Solaris 上运行时我们不会完全失败),

ncores=$(sysctl hw.ncpu); njobs=$(( ncores > 1 ? (ncores - 1) : 1 ))

也许是一个合理的折衷方案(并处理原件未成功返回值1 的情况)。

【讨论】:

    【解决方案2】:

    make 中的-j 参数可以接受关于要使用的内核数量的参数。因此,您可以执行以下操作:

    CORES := $(shell grep -c ^processor /proc/cpuinfo)
    JFLAG := $(shell  echo "-j$$(( $(CORES) - 1 ? $(CORES) - 1 : 1 ))"
    
    all:
        $(MAKE) $(JFLAG) _some_sub_makefile..._
    

    如果您希望您的 make 覆盖传递给它的 -j 标志,您可以执行以下操作:

    ifeq (,$(filter DASHJSET,$(MAKECMDGOALS)))
    
    ABSPATH := $(abspath $(lastword $(MAKEFILE_LIST)))
    
    CORES := $(shell grep -c ^processor /proc/cpuinfo)
    JFLAG := $(shell  echo "-j$$(( $(CORES) - 1 ? $(CORES) - 1 : 1 )))"
    
    all:
        $(MAKE) -C $(ABSPATH) $(JFLAG) DASHJSET $(MAKECMDGOALS)
    
    .PHONY: DASHJSET
    
    fi
    

    【讨论】:

    • grep -c ^processor /proc/cpuinfo 完全仅适用于 Linux —— 例如,根本无法在 Mac 上运行。并且 OP 尚未在问题中标记或以其他方式指示其操作系统。
    • 好点,不过,需要优雅地处理单 CPU 情况。
    猜你喜欢
    • 1970-01-01
    • 2010-09-08
    • 2017-11-10
    • 2016-04-29
    • 2011-07-10
    • 1970-01-01
    • 2017-11-12
    • 2014-05-24
    相关资源
    最近更新 更多