深入理解 Linux Load Average

2023-05-16

一直不解,为什么io占用较高时,系统负载也会变高,偶遇此文,终解吾惑。

#1 load average介绍

##1.1 load average 指标介绍

uptime和top等命令都可以看到load average指标,从左至右三个数字分别表示1分钟、5分钟、15分钟的load average:


uptime

16:04:43 up 20 days, 6:08, 2 users, load average: 0.01, 0.00, 0.00

Load average的概念源自UNIX系统,虽然各家的公式不尽相同,但都是用于衡量正在使用CPU的进程数量和正在等待CPU的进程数量,一句话就是runnable processes的数量。所以load average可以作为CPU瓶颈的参考指标,如果大于CPU的数量,说明CPU可能不够用了。

但是, Linux上不是这样的!

Linux上的load average除了包括正在使用CPU的进程数量和正在等待CPU的进程数量之外,还包括uninterruptible sleep的进程数量。通常等待IO设备、等待网络的时候,进程会处于uninterruptible sleep状态。Linux设计者的逻辑是,uninterruptible sleep应该都是很短暂的,很快就会恢复运行,所以被等同于runnable。然而uninterruptible sleep即使再短暂也是sleep,何况现实世界中uninterruptible sleep未必很短暂,大量的、或长时间的uninterruptible sleep通常意味着IO设备遇到了瓶颈。众所周知,sleep状态的进程是不需要CPU的,即使所有的CPU都空闲,正在sleep的进程也是运行不了的,所以sleep进程的数量绝对不适合用作衡量CPU负载的指标,Linux把uninterruptible sleep进程算进load average的做法直接颠覆了load average的本来意义。所以在Linux系统上,load average这个指标基本失去了作用,因为你不知道它代表什么意思,当看到load average很高的时候,你不知道是runnable进程太多还是uninterruptible sleep进程太多,也就无法判断是CPU不够用还是IO设备有瓶颈。

参考资料:https://en.wikipedia.org/wiki/Load_(computing)

“Most UNIX systems count only processes in the running (on CPU) or runnable (waiting for CPU) states. However, Linux also includes processes in uninterruptible sleep states (usually waiting for disk activity), which can lead to markedly different results if many processes remain blocked in I/O due to a busy or stalled I/O system.“

##1.2 load_average 的含义

###1.2.1 如何衡量通车大桥的负荷

判断系统负荷是否过重,必须理解load average的真正含义。下面,我根据 “Understanding Linux CPU Load” 这篇文章,尝试用最通俗的语言,解释这个问题。

首先,假设最简单的情况,你的电脑只有一个CPU,所有的运算都必须由这个CPU来完成。

那么,我们不妨把这个CPU想象成一座大桥,桥上只有一根车道,所有车辆都必须从这根车道上通过。(很显然,这座桥只能单向通行。)

系统负荷为0,意味着大桥上一辆车也没有。

图片1

系统负荷为0.5,意味着大桥一半的路段有车。

图片 2

系统负荷为1.0,意味着大桥的所有路段都有车,也就是说大桥已经"满"了。但是必须注意的是,直到此时大桥还是能顺畅通行的。

图片 3

桥上在通车的时候, 不光桥上的车影响通车的效率, 后面排队等着还没有上桥的也对桥的拥挤程度有贡献, 因此我们有必要考虑这点, 如果把等待的那些车也算到负载中去, 那么负荷就会 > 1.0.

系统负荷为1.7,意味着车辆太多了,大桥已经被占满了(100%),后面等着上桥的车辆为桥面车辆的70%。以此类推,系统负荷2.0,意味着等待上桥的车辆与桥面的车辆一样多;系统负荷3.0,意味着等待上桥的车辆是桥面车辆的2倍。总之,当系统负荷大于1,后面的车辆就必须等待了;系统负荷越大,过桥就必须等得越久。

图片 4

###1.2.2 类比CPU的系统负荷

CPU的系统负荷,基本上等同于上面的类比。大桥的通行能力,就是CPU的最大工作量;桥梁上的车辆,就是一个个等待CPU处理的进程(process)。

如果CPU每分钟最多处理100个进程,那么系统负荷0.2,意味着CPU在这1分钟里只处理20个进程;系统负荷1.0,意味着CPU在这1分钟里正好处理100个进程;系统负荷1.7,意味着除了CPU正在处理的100个进程以外,还有70个进程正排队等着CPU处理。

为了电脑顺畅运行,系统负荷最好不要超过1.0,这样就没有进程需要等待了,所有进程都能第一时间得到处理。很显然,1.0是一个关键值,超过这个值,系统就不在最佳状态了,你要动手干预了。

###1.2.3 系统负荷的经验法则

1.0是系统负荷的理想值吗?

不一定,系统管理员往往会留一点余地,当这个值达到0.7,就应当引起注意了。经验法则是这样的:

当系统负荷持续大于0.7,你必须开始调查了,问题出在哪里,防止情况恶化。

当系统负荷持续大于1.0,你必须动手寻找解决办法,把这个值降下来。

当系统负荷达到5.0,就表明你的系统有很严重的问题,长时间没有响应,或者接近死机了。你不应该让系统达到这个值。

###1.2.4 多处理器的情形

上面,我们假设你的电脑只有1个CPU。如果你的电脑装了2个CPU,会发生什么情况呢?

2个CPU,意味着电脑的处理能力翻了一倍,能够同时处理的进程数量也翻了一倍。

还是用大桥来类比,两个CPU就意味着大桥有两根车道了,通车能力翻倍了。

图片 6

所以,2个CPU表明系统负荷可以达到2.0,此时每个CPU都达到100%的工作量。推广开来,n个CPU的电脑,可接受的系统负荷最大为n.0。

###1.2.5 多核处理器的情形

芯片厂商往往在一个CPU内部,包含多个CPU核心,这被称为多核CPU。

在系统负荷方面,多核CPU与多CPU效果类似,所以考虑系统负荷的时候,必须考虑这台电脑有几个CPU、每个CPU有几个核心。然后,把系统负荷除以总的核心数,只要每个核心的负荷不超过1.0,就表明电脑正常运行。

怎么知道电脑有多少个CPU核心呢?

"cat /proc/cpuinfo"命令,可以查看CPU信息。"grep -c ‘model name’ /proc/cpuinfo"命令,直接返回CPU的总核心数。

-###1.2.6 最佳观察时长

最后一个问题,"load average"一共返回三个平均值----1分钟系统负荷、5分钟系统负荷,15分钟系统负荷,----应该参考哪个值?

如果只有1分钟的系统负荷大于1.0,其他两个时间段都小于1.0,这表明只是暂时现象,问题不大。

如果15分钟内,平均系统负荷大于1.0(调整CPU核心数之后),表明问题持续存在,不是暂时现象。所以,你应该主要观察"15分钟系统负荷",将它作为电脑正常运行的指标。

#2 Loadavg分析

##2.1 读取 loadavg 的接口 /proc/loadavg

在内核中 /proc/loadavg 是通过 loadavg_proc_show 来读取相应数据,下面首先来看一下load_read_proc的实现:

# https://elixir.bootlin.com/linux/v5.2.13/source/kernel/sched/loadavg.c#L64

/**
 * get_avenrun - get the load average array
 * @loads: pointer to dest load array
 * @offset: offset to add
 * @shift: shift count to shift the result left
 *
 * These values are estimates at best, so no need for locking.
 */
void get_avenrun(unsigned long *loads, unsigned long offset, int shift)
{
    loads[0] = (avenrun[0] + offset) << shift;
    loads[1] = (avenrun[1] + offset) << shift;
    loads[2] = (avenrun[2] + offset) << shift;
}

# http://elixir.bootlin.com/linux/v5.2.13/source/fs/proc/loadavg.c#13
static int loadavg_proc_show(struct seq_file *m, void *v)
{
    unsigned long avnrun[3];

    get_avenrun(avnrun, FIXED_1/200, 0);

    seq_printf(m, "%lu.%02lu %lu.%02lu %lu.%02lu %ld/%d %d\n",
        LOAD_INT(avnrun[0]), LOAD_FRAC(avnrun[0]),
        LOAD_INT(avnrun[1]), LOAD_FRAC(avnrun[1]),
        LOAD_INT(avnrun[2]), LOAD_FRAC(avnrun[2]),
        nr_running(), nr_threads,
        idr_get_cursor(&task_active_pid_ns(current)->idr) - 1);
    return 0;
}

几个宏的定义如下 :


# https://elixir.bootlin.com/linux/v5.2.13/source/include/linux/sched/loadavg.h#L43



#define FSHIFT 11 /* nr of bits of precision */

#define FIXED_1 (1<<FSHIFT) /* 1.0 as fixed-point */

#define LOAD_FREQ (5*HZ+1) /* 5 sec intervals */

#define EXP_1 1884 /* 1/exp(5sec/1min) as fixed-point */

#define EXP_5 2014 /* 1/exp(5sec/5min) */

#define EXP_15 2037 /* 1/exp(5sec/15min) */



#define LOAD_INT(x) ((x) >> FSHIFT)

#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)

根据输出格式,LOAD_INT对应计算的是load的整数部分,LOAD_FRAC计算的是load的小数部分。

将a=avenrun[0] + (FIXED_1/200)带入整数部分和小数部分计算可得:

$$avnrun_i = (avnrun_i + \frac{FIXED_1}{200}) <<11

= (avnrun_i+ 1>>11/200) <<11$$

= \frac{avnrun_i + \frac{2{11}}{200}}{2{11}}$$


LOAD_INT(a) = avnrun_i + \frac{2^{11}}{200}

LOAD_FRAC(a) = ((avenrun[0]%(2^11) + 2^11/200) * 100) / (2^11)
             = (((avenrun[0]%(2^11)) * 100 + 2^10) / (2^11)
             = ((avenrun[0]%(2^11) * 100) / (2^11) + ½

由上述计算结果可以看出,FIXED_1/200在这里是用于小数部分第三位的四舍五入,由于小数部分只取前两位,第三位如果大于5,则进一位,否则直接舍去。

临时变量a/b/c的低11位存放的为load的小数部分值,第11位开始的高位存放的为load整数部分。

因此可以得到a=load(1min) * 2^11

因此有: load(1min) * 2^11 = avenrun[0] + 2^11 / 200

进而推导出: load(1min)=avenrun[0]/(2^11) + 1/200

忽略用于小数部分第3位四舍五入的1/200,可以得到load(1min)=avenrun[0] / 2^11,即:

avenrun[0] = load(1min) * 2^11

avenrun是个陌生的量,这个变量是如何计算的,和系统运行进程、cpu之间的关系如何,在第二阶段进行分析。

##2.2 avenrun 如何表示CPU 负载

内核将 load的计算和load的查看进行了分离,avenrun就是用于连接load计算和load查看的桥梁。
下面开始分析通过avenrun进一步分析系统load的计算。

###2.2.1 avenrun 的更新

avenrun 数组是在 calc_global_load 中进行更新, 在系统更新了 calc_load_update 过了 10 个 jiffies 之后, 会在 do_timer 更新 jiffies 之后, 直接调用 calc_global_load 更新 avenrun 数组


do_timer

    -=> calc_global_load

# https://elixir.bootlin.com/linux/v5.2.13/source/kernel/sched/loadavg.c#L337
/*

 * calc_load - update the avenrun load estimates 10 ticks after the

 * CPUs have updated calc_load_tasks.

 *

 * Called from the global timer code.

 */

void calc_global_load(unsigned long ticks)

{

    unsigned long sample_window;

    long active, delta;



    sample_window = READ_ONCE(calc_load_update);

    if (time_before(jiffies, sample_window + 10))

        return;



    /*

     * Fold the 'old' NO_HZ-delta to include all NO_HZ CPUs.

     */

    delta = calc_load_nohz_fold();

    if (delta)

        atomic_long_add(delta, &calc_load_tasks);



    active = atomic_long_read(&calc_load_tasks);

    active = active > 0 ? active * FIXED_1 : 0;



    avenrun[0] = calc_load(avenrun[0], EXP_1, active);

    avenrun[1] = calc_load(avenrun[1], EXP_5, active);

    avenrun[2] = calc_load(avenrun[2], EXP_15, active);



    WRITE_ONCE(calc_load_update, sample_window + LOAD_FREQ);



    /*

     * In case we went to NO_HZ for multiple LOAD_FREQ intervals

     * catch up in bulk.

     */

    calc_global_nohz();

}

calc_load_tasks 可以理解为当前系统中 RUNNING(R状态)进程和 uninterruptible(D状态)进程的总数目.

active_tasks为系统中当前贡献load的task数nr_active乘于FIXED_1,用于计算avenrun

avenrun 的计算方法 calc_load 如下所示:


# https://elixir.bootlin.com/linux/v5.2.13/source/include/linux/sched/loadavg.h#L19

/*

 * a1 = a0 * e + a * (1 - e)

 */

static inline unsigned long

calc_load(unsigned long load, unsigned long exp, unsigned long active)

{

    unsigned long newload;



    newload = load * exp + active * (FIXED_1 - exp);

    if (active >= load)

        newload += FIXED_1-1;



    return newload / FIXED_1;

}

用avenrun(t-1)和avenrun(t)分别表示上一次计算的avenrun和本次计算的avenrun,则根据CALC_LOAD宏可以得到如下计算:

avenrun(t)=(avenrun(t-1) * EXP_N + nr_active * FIXED_1*(FIXED_1 – EXP_N)) / FIXED_1

      = avenrun(t-1) + (nr_active*FIXED_1 – avenrun(t-1)) * (FIXED_1 -EXP_N) / FIXED_1

推导出:

avenrun(t) – avenrun(t-1) = (nr_active*FIXED_1 – avenrun(t-1)) * (FIXED_1 – EXP_N) / FIXED_1

将第一阶段推导的结果代入上式,可得:

(load(t) – load(t-1)) * FIXED_1 = (nr_active – load(t-1)) * (FIXED_1 – EXP_N)

进一步得到nr_active变化和load变化之间的关系式:

load(t) – load(t-1) = (nr_active – load(t-1)) * (FIXED_1 – EXP_N) / FIXED_1

这个式子可以反映的内容包含如下两点:

1)当nr_active为常数时,load会不断的趋近于nr_active,趋近速率由快逐渐变缓

2)nr_active的变化反映在load的变化上是被降级了的,系统突然间增加10个进程,

1分钟load的变化每次只能够有不到1的增加(这个也就是权重的的分配)。

另外也可以通过将式子简化为:

load(t)= load(t-1) * EXP_N / FIXED_1 + nr_active * (1 - EXP_N/FIXED_1)

这样可以更加直观的看出nr_active和历史load在当前load中的权重关系 (多谢任震宇大师的指出)


#define EXP_1 1884 /* 1/exp(5sec/1min) as fixed-point */ 

#define EXP_5 2014 /* 1/exp(5sec/5min) */ 

#define EXP_15 2037 /* 1/exp(5sec/15min) */

1分钟、5分钟、15分钟对应的EXP_N值如上,随着EXP_N的增大,(FIXED_1 – EXP_N)/FIXED_1值就越小,

这样nr_active的变化对整体load带来的影响就越小。对于一个nr_active波动较小的系统,load会

不断的趋近于nr_active,最开始趋近比较快,随着相差值变小,趋近慢慢变缓,越接近时越缓慢,并最

终达到nr_active。如下图所示:

文件:load 1515.jpg(无图)

也因此得到一个结论,load直接反应的是系统中的nr_active。 那么nr_active又包含哪些? 如何去计算

当前系统中的nr_active? 这些就涉及到了nr_active的采样。

###2.2.2 calc_load_tasks 的更新


calc_load_tasks 常规情况下在 tick 中进行更新.

this_rq->calc_load_active 记录了当前 RQ 上 RUNNING(R状态)线程和 uninterruptible(D状态)线程的总数.

delta 为上次更新到现在 this_rq 上 R+D 状态进程的增量情况.

calc_load_tasks 则保存了当前系统中进程 R+D 状态进程的总数目.

LOAD_FREQ 被定义成 5HZ+1(5S 之后), 是更新 this_rq->calc_load_active 和 全局的 calc_load_tasks 的时间间隔, 每 LOAD_FREQ 才会更新一次.

this_rq->calc_load_update 总表示当前RQ 上下次执行 calc_global_load_tick 时可以进行更新的时间

在 calc_global_load_tick 中

  1. 先检查 calc_load_update 到期没,

  2. 到期后,

先更新了 this_rq->calc_load_active

接着更新了全局的 calc_load_tasks.

最后设置 this_rq->calc_load_update 为 LOAD_FREQ(5S) 之后.

因此每隔 LOAD_FREQ的时间, 系统在calc_global_load_tick 中基于 this_rq->calc_load_active, 更新 全局的calc_load_tasks.


# https://elixir.bootlin.com/linux/v5.2.13/source/kernel/sched/loadavg.c#L79

static long calc_load_fold_active(struct rq *this_rq)

{

        long nr_active, delta = 0;

 

        nr_active = this_rq->nr_running;

        nr_active += (long) this_rq->nr_uninterruptible;

 

        if (nr_active != this_rq->calc_load_active) {

                delta = nr_active - this_rq->calc_load_active;

                this_rq->calc_load_active = nr_active;

        }

 

        return delta;

}



# https://elixir.bootlin.com/linux/v5.2.13/source/kernel/sched/loadavg.c#L369

/*

 * Called from scheduler_tick() to periodically update this CPU's

 * active count.

 */

void calc_global_load_tick(struct rq *this_rq)

{

    long delta;



    if (time_before(jiffies, this_rq->calc_load_update))

        return;



    delta = calc_load_fold_active(this_rq, 0);

    if (delta)

        atomic_long_add(delta, &calc_load_tasks);



    this_rq->calc_load_update += LOAD_FREQ;

}

而 avenrun 则在 calc_load_update 更新 10 ticks 之后通过 calc_global_load 更新.

#3 参考资料

https://www.cnblogs.com/qqmomery/p/6267429.html

http://linuxperf.com/?p=176

https://scoutapm.com/blog/understanding-load-averages

http://www.ruanyifeng.com/blog/2011/07/linux_load_average_explained.html

http://www.blogjava.net/cenwenchu/archive/2008/06/30/211712.html

https://www.cnblogs.com/qqmomery/p/6267429.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

深入理解 Linux Load Average 的相关文章

  • 为什么 OS X 和 Linux 之间的 UTF-8 文本排序顺序不同?

    我有一个包含 UTF 8 编码文本行的文本文件 mac os x cat unsorted txt foo foo 津 如果它有助于重现问题 这里是文件中确切字节的校验和和转储 以及如何自己生成文件 在 Linux 上 使用base64 d
  • Docker忽略limits.conf(试图解决“打开文件太多”错误)

    我正在运行一个 Web 服务器 该服务器正在处理数千个并发 Web 套接字连接 为了实现这一点 在 Debian linux 我的基本镜像是 google debian wheezy 在 GCE 上运行 上 打开文件的默认数量设置为 100
  • Python glob,操作系统,相对路径,将文件名放入列表中[重复]

    这个问题在这里已经有答案了 我正在尝试创建一个目录中所有文件的列表 其中文件名以 root 结尾 在阅读了论坛中的一些文章后 我尝试使用 glob 和 os listdir 的基本策略 但我都遇到了麻烦 首先 当我使用 import glo
  • BASH:输入期间按 Ctrl+C 会中断当前终端

    我的 Bash 版本是 GNU bash version 4 3 11 1 release x86 64 pc linux gnu 我有一段这样的代码 while true do echo n Set password read s pas
  • Crontab 每 5 分钟一次 [关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 我如何告诉 crontab 每 5 分钟运行一次 但从每小时的第二分钟开始 换句话说 我想在以下时间执行我的脚本minute 5 2 例如 我的脚本应
  • 为 Linux 编译 Objective-C 应用程序(API 覆盖范围)

    我可能在这里问一些奇怪的问题 但我不确定从哪里开始 问题是我正在考虑使用 Obj C 和 Foundation 类在 Mac 上编写一个命令行工具 但存在一个非常大的风险 那就是我希望能够为不同的 Linux 发行版编译它 以便将来作为服务
  • 在汇编中使用 printf 会导致管道传输时输出为空,但可以在终端上使用

    无输出 https stackoverflow com questions 54507957 printf call from assembly do not print to stdout即使在终端上 当输出不包含换行符时也有相同的原因
  • ssh 连接超时

    我无法在 git 中 ssh 到 github bitbucket 或 gitlab 我通常会收到以下错误消息 如何避免它 输出 ssh T email protected cdn cgi l email protection i ssh
  • 为什么 Linux 原始套接字的 RX 环大小限制为 4GB?

    背景 我试图mmap 我的原始套接字的 RX 环形缓冲区64 bitLinux 应用程序 我的环由 4096 个块组成 每个块大小为 1MB 总共 4GB 请注意 每个 1MB 块中可以有许多帧 如果您好奇 请参阅此文档了解背景信息 htt
  • 执行命令而不将其保留在历史记录中[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 在进行软件开发时 经常需要在命令行命令中包含机密信息 典型示例是将项目部署到服务器的凭据设置为环境变量 当我不想将某些命令存储在命令历史记
  • Linux 中 m 标志和 o 标志将存储在哪里

    我想知道最近收到的路由器通告的 m 标志和 o 标志的值 从内核源代码中我知道存储了 m 标志和 o 标志 Remember the managed otherconf flags from most recently received R
  • SSH,运行进程然后忽略输出

    我有一个命令可以使用 SSH 并在 SSH 后运行脚本 该脚本运行一个二进制文件 脚本完成后 我可以输入任意键 本地终端将恢复到正常状态 但是 由于该进程仍在我通过 SSH 连接的计算机中运行 因此任何时候它都会登录到stdout我在本地终
  • ALSA:snd_pcm_writei 调用时缓冲区不足

    当运行我最近从灰烬中带回来的旧程序时 我遇到了缓冲区不足的情况 该程序将原始声音文件完全加载到内存中 2100 字节长 525 帧 并准备 ALSA 进行输出 44 1khz 2 通道 有符号 16 位 if err snd pcm set
  • 为什么 Linux 没有 DirectX API?

    在考虑现代显卡的 Windows 系统上 DirectX API 的驱动程序端实现时 我想知道为什么此实现在非 Windows 系统 尤其是 Linux 上不可用 由于明显缺乏此功能 我只能假设有一个我无视的充分理由 但在我的原始理解中 我
  • 在 C 中使用单个消息队列是否可以实现双向通信

    我希望服务器向客户端发送一些消息 并让客户端确认它 我被分配了这个任务 我可以在 C linux 中使用单个消息队列来完成它还是我需要创建两个 谢谢 是的 可以使用 sysV 消息队列来做到这一点 从您之前的问题来看 您正在使用该队列 您可
  • 调用 printf 系统子例程在汇编代码中输出整数错误[重复]

    这个问题在这里已经有答案了 来回 在windows7控制台窗口中运行gcc s2 asm 然后生成一个exe文件 运行a exe 然后崩溃 为什么 s2 asm 代码由以下源代码生成 int m m 1 iprint m s2 asm请参考
  • docker 非 root 绑定安装权限,WITH --userns-remap

    all 尝试让绑定安装权限正常工作 我的目标是在容器中绑定安装卷 以便 a 容器不以 root 用户身份运行入口点 二 docker daemon 配置了 userns remap 这样容器 主机上没有 root c 我可以绑定挂载和读 写
  • 就分页分段内存而言的程序寿命

    我对 x86 Linux 机器中的分段和分页过程有一个令人困惑的概念 如果有人能澄清从开始到结束所涉及的所有步骤 我们将很高兴 x86 使用分页分段内存技术进行内存管理 任何人都可以解释一下从可执行的 elf 格式文件从硬盘加载到主内存到它
  • 如何根据标签将单个 XML 文件拆分为多个

    我有一个带有标签的 XML 文件 我想像这样分割文件
  • 使用循环在 C 中管道传输两个或多个 shell 命令

    我正在尝试执行ls wc l通过 C 语言程序 而不是使用命令行 这是我当前的工作代码 int main int pfds 2 pipe pfds pid t pid fork if pid 0 The child process clos

随机推荐

  • Pytorch : Dataset和DataLoader

    一 综述 Dataset 对数据进行抽象 xff0c 将数据包装为Dataset类 DataLoader 在 Dataset之上对数据进行进一步处理 xff0c 包括进行乱序处理 xff0c 获取一个batch size的数据等 二 Dat
  • 特征工程

    一 数据读取 1 1 读取CSV文件 1 1 1 原文件内容 1 1 2 读取csv span class token keyword import span csv csv file span class token operator 6
  • 代码命名规范

    代码命名规范 现在是2016年12月30日中午12点35分 xff0c 这是我第一次写博客 xff0c 用的是markdown编辑器 xff0c 还不太会用 今天就先简单的写一下 xff0c 看看写出来的效果是什么样的 xff01 xff0
  • Ubuntu18.04 离线安装nginx

    由于服务器位于内网环境且无法访问互联网 xff0c 需要离线安装nginx xff0c ubuntu18 04离线安装软件也并不复杂 xff0c 只是需要较大的耐心去搜集所需的包 xff0c 不过大家不用担心 xff0c 我已经为大家准备好
  • easyui combobox动态绑定数据

    1 jsp上的写法 lt input span class hljs keyword class span 61 span class hljs string 34 easyui combobox 34 span id 61 span cl
  • Echarts(二、柱状图(各参数详细描述))

    1 jsp页面 span class hljs tag lt span class hljs title body span gt span span class hljs tag lt span class hljs title div
  • js中级脚本算法

    1区间求值算法挑战 span class hljs function span class hljs keyword function span span class hljs title sumAll span span class hl
  • 常用easyUI -icon 图标

    1 样式 代码 xff1a lt DOCTYPE html gt lt html lang 61 34 en 34 gt lt head gt lt meta charset 61 34 UTF 8 34 gt lt title gt Ea
  • vue与后台交互数据(vue-resource)

    需要引入库 xff1a vue resource lt script src 61 34 https cdn jsdelivr net vue resource 1 0 3 vue resource min js 34 gt lt scri
  • Tensorflow——jupyter notebook调用某个库时,出现找不到这个库情况的解决方案

    1 激活tensorflow环境 终端下输入 xff1a source activate tensorflow 2 进入jupyter notebook 出现如下问题 xff1a 没有找到matplotlib库 3 解决方法 在tensor
  • 组合排序题目汇总(排列组合、卡特兰数和递归思想)

    组合排序题目汇总 排列组合矩阵走法A必须在B左边站队互不相邻站队分糖果球放入桶吃糖 卡特兰数括号匹配进出栈顺序 售票顺序二叉树不同的结构数高矮排列 递归思想信封装信 排列组合 矩阵走法 在6 9的方格中 xff0c 以左上角为起点 xff0
  • java.lang.IllegalStateException 错误原因及解决方法小记

    java lang IllegalStateException Cannot perform this operation because the connection pool has been closed at android dat
  • 架构设计三原则

    1 简单原则 xff1b 分析完业务场景的结构复杂性和逻辑复杂性后 xff0c 从业务场景和解决问题的角度出发 xff0c 选择和设计能够满足需求的方案 在简单架构和复杂架构都能满足要求的时候 xff0c 优先选择简单架构 xff0c 因为
  • mybatis的resultMap property爆红

    span class token tag span class token tag span class token punctuation lt span resultMap span span class token attr name
  • Ubuntu20.04 rc-local 配置开机自启动脚本

    1 rc local服务简介 Linux中的rc local服务是一个开机自动启动的 xff0c 调用开发人员或系统管理员编写的可执行脚本或命令的 xff0c 它的启动顺序是在系统所有服务加载完成之后执行 ubuntu20 04系统已经默认
  • zynq7000 linux axi-gpio驱动:重置axi-gpio驱动方法

    linux gpio 从内核空间导出到用户空间 petalinux 在制作 Linux 系统时 xff0c 会自动的将 gpio 从内核空间导出到用户空间 xff0c 在用户空间下可以通过 sysfs 方式控制 gpio xff1b 用户空
  • AndroidManifest的理解

    最近做二次开发 xff0c 修改别人代码的时候发现清单文件中多了很多奇怪的属性和标签 xff08 自己以前没见过的 xff09 xff0c 在不明白的情况下直接开发出现了很多奇怪的问题 所以痛下决心 xff0c 重新复习下这些基础知识 以下
  • 使用 zsh 后HOME/END 键以及小键盘失效

    1 问题描述 zsh是一款超赞的shell工具 xff0c 但是配置复杂 xff0c 有个闲着没事的程序员 xff0c 弄了一个开源项目 robbyrussell oh my zsh 截止目前 xff0c 58 8k 43 star就知道有
  • 开启内核地址随机化KASLR后, qemu 调试 kernel 不能设置断点

    1 问题 gdb 断点异常 这几天更新了 qemu 然后在进行 gdb 调试的时候 发现断点断不住了 之前都是正常的 从来没有出现过这种情况啊 继续分析下看看是哪里出现的异常 2 原因分析 难道是 gdb 或者 QEMU 出现 BUG 了
  • 深入理解 Linux Load Average

    一直不解 xff0c 为什么io占用较高时 xff0c 系统负载也会变高 xff0c 偶遇此文 xff0c 终解吾惑 1 load average介绍 1 1 load average 指标介绍 uptime和top等命令都可以看到load