Running Build Commands Nicely

Running Build Commands Nicely

很好的运行构建命令

Mar 30, 2019  2019年3月30日

All Unix systems come with a nice command that runs a program with a modified “niceness” value. This niceness value is used as a scheduling priority by the kernel process scheduler, and the default value for new tasks is 0. When the system is overloaded the kernel will prioritize processes with a negative niceness value, and likewise it will deprioritize processes with a positive niceness value.

所有的Unix系统都带有一个很好的命令,可以运行一个修改“niceness”值的程序。这个niceness值是被内核进程调度器用做调度优先级。新任务的默认值是0,当系统过载时,内核将以负的niceness值优先处理进程,并且同样的他将以正值递减进程。

You’ll see the niceness value for processes on your system in the NI column when you run top or htop. If you run it on a typical system you’ll see that nearly all programs have the default niceness of 0, and you may also see a few high priority system processes or kernel threads that are configured with a negative nice value.

当你运行top或者htop命令的时候,你将会在系统中的NI列中可看到niceness值。如果你在典型系统中运行它,你将会看到几乎所有的程序默认的niceness值都是0,并且你也会看到一些高优先级的系统进程或者内核线程都被配置成负数。

The Linux kernel has a fairly advanced process scheduler: since Linux 2.6.23 (released in 2007) the default process scheduler is CFS (the Completely Fair Scheduler), which uses various heuristics to try to automatically detect “interactive” tasks and give them scheduling priority when the system is under high load. The idea is that if you’re under high load (say, you’re compiling a large C++ project), CFS uses some heuristics that attempt to tell that the Emacs process you’re using is “interactive” because it’s waiting for keyboard I/O, and therefore CFS will automatically try to make sure the Emacs process gets a higher scheduling priority than the non-interactive compiler processes, even if they’re both running with the default niceness of 0.

这个Linux内核有一个相当高级的进程调度器:从Linux2.6.23(在2007年发布的),默认的程序调度器是CFS(完全公平的调度器),它使用各种启发式的方法来尝试自动检测“交互式”的任务,并且当系统在高负载运行的情况下给与他们优先调度。这个想法是如果你处于高负荷(例如,你挣在编译一个大型C++项目),CFS使用一些试探式的方法去试图告诉你你正在使用的交互式Emacs进程,是因为它在等待键盘I/O,因此CFS将会自动的试着确定Emacs进程比非交互式编译器进程获取更高的优先调度权。即使他们两个都默认以niceness0运行着。

This is a nifty trick, but it doesn’t always work perfectly. For example, I’ve found that if I’m compiling code big projects Firefox will slow down, especially if I’m doing things like watching videos. I could run my compilation tasks using the nice command (or even renice an existing command) but it’s not my job to remember to do that, my computer should do it for me.

这是一个很实用的计策,但是并不是总是完美的。例如,我发现如果我正在编码一个大型项目火狐运行速度将会变慢,尤其是如果我看视频,我将会使用很好的命令去运行我的编译任务(或者甚至重新定义现存命令),但是记住去做这件事的不是我的,应该我是的电脑为我做这件事。

Therefore I have use the following code in my bash configs that automatically run non-interactive tasks that I expect to use a lot of CPU to run nicely:

因此,在我的基础配置文件中我需要使用如下命令去自动运行非交互式命令,我希望这些命令将会让大量的CPU运行的很好:

# Check if a command exists.检查命令是否存在
exists() { command -v "$1" &>/dev/null; }

# Alias a command to run nicely.
nicealias() {
  if exists "$1"; then
    # shellcheck disable=2139,2140
    alias "$1"="nice $1"
  fi
}

# Automatically run these commands nicely.
nicealias bazel
nicealias bzip2
nicealias fedpkg
nicealias gzip
nicealias make
nicealias mock
nicealias rpmbuild
nicealias xz

You can check that this actually works as expected using the type Bash builtin:

你可以使用bash 内置命令去检查它实际上是否按预期工作

# Check that "make" is actually aliased to run nicely.
$ type make
make is aliased to `nice make'

Dealing With Subcommands

The above works well for simple commands, but tools that use “subcommands” are a bit trickier. For example, I begrudgingly use npm from time to time. I want npm subcommands like npm run to run unmodified, with the default niceness. However subcommands like npm install and npm run build download and compile (or transpile) a lot of Javascript and possibly even C++, and that can use up a lot of CPU time.

It’s possible to handle this case using a Bash function, but it’s a bit tricky. Here’s how I do it.

处理子命令上面的方法对简单命令有效,但是使用子命令工具要复杂一些。比如,我不喜欢时不时的使用npm命令,我希望npm子命令,像npm run,以默认的未修改niceness的情况下运行。然而像,npm安装和npm运行构建下载编译或者转义大量的js甚至可能是C++都会花费大量的cpu的时间。

It’s possible to handle this case using a Bash function, but it’s a bit tricky. Here’s how I do it.

使用bash函数可以处理这种情况但是有些棘手,我是这样做的

# Force "npm install" and "npm run build" to run nicely
npm() {
  local nicecmd=()
  if [[ "$1" == "install" || ( "$1" == "run" && "$2" == "build*" ) ]]; then
    nicecmd+=(nice)
  fi
  # shellcheck disable=2230
  "${nicecmd[@]}" "$(which npm)" "$@"
}

Note carefully I use the which command to locate the actually npm command on the filesystem (e.g. /usr/bin/npm) when constructing the cmd array. Previously I used the more portable command -v builtin in the implementation of my nicealias function, but that won’t work here. This is because command -v will search the shell environment, which can cause the npm function here to call itself recursively without terminating!

请注意,当构造cmd 数组时候,我使用which命令去定位实际上npm命令在文件系统上的位置。(例如/usr/bin/npm)。以前我在我的nicealias方法实现中使用更多的可移植的内置命令-v。但是在这里就行不通了。这是因为命令-v将会在shell的环境中去搜索。可能导致npm函数在这里递归的调用自己不终止。

To check that this is actually set up correctly, source the file where you defined the function and check what npm means to the shell using the Bash type builtin:

检查是否安装正确,在你定义方法的地方获取这个文件,并且使用bash类型的内置函数检查npm对shell的意义。

# Type tells us that npm is actually a Bash function
$ type npm
npm is a function
npm ()
{
    local nicecmd=();
    if [[ "$1" == "install" || ( "$1" == "run" && "$2" == "build*" ) ]]; then
        nicecmd+=(nice);
    fi;
    "${nicecmd[@]}" "$(which npm)" "$@"
}

Note that this is not what which will tell you, as which merely searches $PATH without regard to the shell environment it’s run in:

注意,这并不是要告诉您,仅仅搜索$PATH,却并没有关注shell的运行环境。

# Which just searches for npm in $PATH, and won't notice the function
$ which npm
/usr/bin/npm
发布了88 篇原创文章 · 获赞 33 · 访问量 19万+

猜你喜欢

转载自blog.csdn.net/ccmedu/article/details/100773843