博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
linux性能评估-cpu概念理解篇
阅读量:5862 次
发布时间:2019-06-19

本文共 10561 字,大约阅读时间需要 35 分钟。

1.影响Linux服务器性能的因素

1.1 操作系统级

性能调优是找出系统瓶颈并消除这些瓶颈的过程。 很多系统管理员认为性能调优仅仅是调整一下内核的参数即可解决问题, 事实上情况并不是这样。 性能调优是实现操作系统的各个子系统之间的平衡性,这些子系统包括:

  •        CPU
  •        内存
  •        磁盘I/O带宽
  •        网络I/O带宽

子系统之间相互依存,任何一个子系统的负载过度都能导致其他子系统出现问题,例如:

  • 大量的 page-in IO 请求可能导致内存队列被塞满
  • 网卡的巨量吞吐可能导致 CPU 资源耗尽
  • 系统尝试保持释放内存队列时可能耗尽 CPU 资源
  • 来自内存的大量磁盘写入请求可能导致 CPU 资源和 IO 通道耗尽

性能调优的前提是找出系统瓶颈之所在, 尽管问题看似由某个子系统所导致, 然而这很可能是另外一个子系统的过载所引起的。

1.2 程序应用级

为了明白从何处开始着手调整性能瓶颈, 弄清被分析系统的性能表现是首要任务。 任何系统的应用常可分为以下两类:

  • IO 限制型——一个 IO 限制型的应用需要大量的内存和基础存储设备占用。 因其需要大量的数据读写请求,此类应用对 CPU 和网络需求不高(除非存储系统在网络上) 。
  •  IO 限制型应用使用 CPU 资源来进行 IO 操作且常进入睡眠状态。 数据库应用常被认为属于此类。
  • CPU 限制型——一个 CPU 限制型应用需要大量的 CPU 资源,来进行批量的处理或大量的计算。大容量 web 服务,mail 服务,以及任何类型的渲染服务都被归到此类。

1.3.系统性能评估标准

我们在进行压测时,可以用来判断系统好坏的一个标准,可以参考如下表格的一个标准:

影响性能因素

评判标准

糟糕

CPU

user% + sys%< 70%

user% + sys%= 85%

user% + sys% >=90%

内存

Swap In(si)=0

Swap Out(so)=0

Per CPU with 10 page/s

More Swap In & Swap Out

磁盘

iowait % < 20%

iowait % =35%

iowait % >= 50%

其中:

       %user:表示CPU处在用户模式下的时间百分比。
       %sys:表示CPU处在系统模式下的时间百分比。
       %iowait:表示CPU等待输入输出完成时间的百分比。
       swap in:即si,表示虚拟内存的页导入,即从SWAP DISK交换到RAM。
       swap out:即so,表示虚拟内存的页导出,即从RAM交换到SWAP DISK。

2.理解“平均负载”

2.1什么是平均负载?
(1)uptime

  • 15:04:40 #系统当前时间
  • up 31 days, 21:45#系统运行时间
  • 1 user#正在登录用户数
  • load average: 0.01, 0.01, 0.00
  • 最后三个数字,依次则是过去 1 分钟、5 分钟、15 分钟的平均负载(Load Average)

平均负载:是指单位时间内,系统处于可运行状态和不可中中断状态的平均进程数,也就是平均活跃进程数,它和 CPU 使用率没有直接关系。

这里需要注意的是:load average这个输出值,这三个值的大小一般不能大于系统CPU的个数。例如,本输出中系统有16个CPU,如果load average的三个值长期大于16时,说明CPU很繁忙,负载很高,可能会影响系统性能,但是偶尔大于16时,倒不用担心,一般不会影响系统性能。相反,如果load average的输出值小于CPU的个数,则表示CPU还有空闲的时间片,比如本例中的输出,CPU是非常空闲的。
可以通过查询文件/proc/loadavg获取系统在前一分钟、前五分钟和前十五分钟的平均负载以及当前运行的进程、系统的进程数和上一次调度运行的进程。

(2)top

  • 前五行是系统整体的统计信息。
  • 第一行是任务队列信息,同 uptime 命令的执行结果。其内容如下:当前时间;系统运行时间,格式为时:分;当前登录用户数;系统负载,即任务队列的平均长度。
  • 第二、三行为进程和CPU的信息。当有多个CPU时,这些内容可能会超过两行。
  • 内容如下:Tasks: 175 total 进程总数;1 running正在运行的进程数;338 sleeping睡眠的进程数;0 stopped停止的进程数;0 zombie僵尸进程数
  • Cpu(s):1.4% us用户空间占用CPU百分比
  • 1.4%sy内核空间占用CPU百分比
  • 0.0%ni用户进程空间内改变过优先级的进程占用CPU百分比
  • 97.2%id空闲CPU百分比
  • 0.0%wa等待输入输出的CPU时间百分比
  • 0.0%si swap in,表示虚拟内存的页导入,即从SWAPDISK交换到RAM。
  • 0.0%st swap out,表示虚拟内存的页导出,即从RAM交换到SWAPDISK。
  • PR:操作系统给进程的安排的优先级。这个值表示进程调度器分配给进程的时间片长度。单位是时钟个数。如果一个Linux系统的时间片是10ms,那么PID是2718的进程在执行了200ms后,才会进行进程切换。 
  • RES:进程占用的物理内存大小。          
  • VIRT:物理内存+虚拟内存。  

2.2平均负载和CPU使用率

平均负载是指单位时间内,处于可运行状态和不可中断状态的进程数。它不仅包括了正在使用CPU的进程,还包括等待CPU和等待I/O的进程。

CPU使用率,是单位时间内CPU繁忙情况的统计,跟平均负载并不一定完全对应。
CPU 密集型进程,使用大量 CPU 会导致平均负载升高,此时这两者时一致的。
I/O 密集型进程,等待 I/O 也会导致平均负载升高,但CPU使用率不一定很高。
大量等待 CPU 的进程调度也会导致平均负载升高,此时的CPU使用率也会比价高。

3.CPU 上下文切换

3.1 什么是上下文切换

上下文切换CPU切换到另一个进程需要保存当前进程的状态并恢复另一个进程的状态:当前运行任务转为就绪(或者挂起、中断)状态,另一个被选定的就绪任务成为当前任务。进程调度包括保存当前任务的运行环境,恢复将要运行任务的运行环境。

1.vmstat使用
vmstat是一个常用的系统性能分析工具,主要用来分析系统的内存使用情况,也常来分析CPU上下文切换和中断的次数。
#每隔 5 秒输出 1 组数据

  • cs :每秒上下文切换的次数;
  • in:每秒中断的次数;
  • r:就绪队列的长度,也就是正在运行的等待CPU的进程数;
  • b:处于不可中断睡眠状态的进程数;

以上vmstat只给出了系统总体的上下文切换的情况,使用pidstat,并加上-w,可以查看每个进程上下文切换的情况;

例如:

这里有我们需要重点关注的对象,就是cswch(每秒自愿上下文切换)的次数,nvcswch(每秒非自愿上下文切换)的次数。它们意味着不同的性能问题:

所谓自愿上下文切换,是指进程无法获取所需资源,导致的上下文切换。比如说,I/O,内存等系统资源不足时,就会发生自愿上下文切换。
而非而非自愿上下文切换,则是指进程由于时间片已到等原因,被系统强制调度,进而发生的上下文切换。比如说,大量进程都在争抢CPU时,就容易发生非自愿上下文切换。

4.不可中断进程和僵尸进程

4.1 查看进行状态

使用top命令查看:

  • R 是 Running 或 Runnable 的缩写,表示进程在 CPU 的就绪队列中,正在运行或者正在等待运行。
  • D 是 Disk Sleep 的缩写,也就是不可中断状态睡眠(Uninterruptible Sleep),一般表示进程正在跟硬件交互,并且交互过程不允许被其他进程或中断打断。
  • S 是 Interruptible Sleep 的缩写,也就是可中断状态睡眠,表示进程因为等待某个事件而被系统挂起。当进程等待的事件发生时,它会被唤醒并进入 R 状态。
  • Z 是 Zombie 的缩写,它表示僵尸进程,也就是进程实际上已经结束了,但是父进程还没有回收它的资源(比如进程的描述符、PID 等)。
  • I 是 Idle 的缩写,也就是空闲状态,用在不可中断睡眠的内核线程上。前面说了,硬件交互导致的不可中断进程用 D 表示,但对某些内核线程来说,它们有可能实际上并没有任何负载,用Idle 正是为了区分这种情况。要注意,D 状态的进程会导致平均负载升高, I 状态的进程却不会。

4.2僵尸进程的影响

一旦父进程没有处理子进程的终止,还一直保持运行状态,那么子进程就会一直处于僵尸状态。大量的僵尸进程会用尽 PID 进程号,导致新进程不能创建,所以这种情况一定要避免。

5.应用的CPU使用率达到100%,应该怎么办?

5.1怎么查看 CPU 使用率

使用命令top

  • user(通常缩写为 us),代表用户态 CPU 使用率.
  • nice(通常缩写为 ni),代表低优先级用户态 CPU 使用率,也就是进程的 nice 值被调整为 1-19 之间时的 cpu使用率。
  • system(通常缩写为 sys),代表内核态 CPU 使用率。
  • idle(通常缩写为 id),代表空闲CPU。
  • iowait(通常缩写为 wa),代表等待 I/O 的 CPU使用率。
  • irq(通常缩写为 hi),代表处理硬中断的 CPU 使用率。
  • softirq(通常缩写为 si),代表处理软中断的 CPU使用率。
  • steal(通常缩写为 st),代表当系统运行在虚拟机中的时候,被其他虚拟机占用的 CPU 使用率。

5.2 CPU 使用率过高怎么办?

(1)第一种常见用法是 perf top

类似于 top,它能够实时显示占用 CPU 时钟最多的函数或者指令,因此可以用来查找热点函数,使用界面如下所示:

  • 第一列 Overhead ,是该符号的性能事件在所有采样中的比例,用百分比来表示。
  • 第二列 Shared ,是该函数或指令所在的动态共享对象(Dynamic Shared Object),如内核、进程名、动态链接库名、内核模块名等。
  • 第三列 Object ,是动态共享对象的类型。比如 [.]表示用户空间的可执行程序、或者动态链接库,而 [k] 则表示内核空间。
  • 最后一列 Symbol 是符号名,也就是函数名。当函数名未知时,用十六进制的地址来表示。

(2)第二种常见用法,也就是 perf record 和 perf report

perf record 则提供了保存数据的功能,保存后的数据需要你用 perf report 解析展示.

如下:

$ perf record -p -g 进程pid # 按 Ctrl+C 终止采样,加上g参数可以显示函数的调用关系

$ perf report # 展示类似于 perf top 的报告,报告展示如下:

总结:

  • CPU 使用率是最直观和最常用的系统性能指标,更是我们在排查性能问题时,通常会关注的第一个指标。所以我们更要熟悉它的含义,尤其要弄清楚用户(%user)、Nice(%nice)、系统(%system) 、等待 I/O(%iowait) 、中断(%irq)以及软中断(%softirq)这几种不同 CPU 的使用率。比如说:
  • a.用户 CPU 和 Nice CPU 高,说明用户态进程占用了较多的 CPU,所以应该着重排查进程的性能问题。
  • b.系统 CPU 高,说明内核态占用了较多的 CPU,所以应该着重排查内核线程或者系统调用的性能问题。
  • c.I/O 等待 CPU 高,说明等待 I/O 的时间比较长,所以应该着重排查系统存储是不是出现了 I/O 问题。
  • d.软中断和硬中断高,说明软中断或硬中断的处理程序占用了较多的CPU,所以应该着重排查内核中的中断服务程序。

5.怎么理解Linux软中断

1.从“取外卖”看中断

中断是系统用来响应硬件设备请求的一种机制,它会打断进程的正常调度和执行,然后调用内核中的中断处理程序来响应设备的请求。

中断的作用:

比如说你订了一份外卖,但是不确定外卖什么时候送到,也没有别的方法了解外卖的进度,但是,配送员送外卖是不等人的,到了你这儿没人取的话,就直接走人了。所以你只能苦苦等着,时不时去门口看看外卖送到没,而不能干其他事情。

不过呢,如果在订外卖的时候,你就跟配送员约定好,让他送到后给你打个电话,那你就不用苦苦等待了,就可以去忙别的事情,直到电话一响,接电话、取外卖就可以了。

这里的“打电话”,其实就是一个中断。没接到电话的时候,你可以做其他的事情;只有接到了电话(也就是发生中断),你才要进行另一个动作:取外卖。

这个例子你就可以发现,中断其实是一种异步的事件处理机制,可以提高系统的并发处理能力.

由于中断处理程序会打断其他进程的运行,所以,为了减少对正常进程运行调度的影响,中断处理程序就需要尽可能快地运行。如果中断本身要做的事情不多,那么处理起来也不会有太大问题;但如果中断要处理的事情很多,中断服务程序就有可能要运行很长时间。

特别是,中断处理程序在响应中断时,还会临时关闭中断。这就会导致上一次中断处理完成之前,其他中断都不能响应,也就是说中断有可能会丢失。

那么还是以取外卖为例。假如你订了 2 份外卖,一份主食和一份饮料,并且是由 2 个不同的配送员来配送。这次你不用时时等待着,两份外卖都约定了电话取外卖的方式。但是,问题又来了。

当第一份外卖送到时,配送员给你打了个长长的电话,商量发票的处理方式。与此同时,第二个配送员也到了,也想给你打电话。

但是很明显,因为电话占线(也就是关闭了中断响应),第二个配送员的电话是打不通的。所以,第二个配送员很可能试几次后就走掉了(也就是丢失了一次中断)。

2.软中断

如果你弄清楚了“取外卖”的模式,那对系统的中断机制就很容易理解了。事实上,为了解决中断处理程序执行过长和中断丢失的问题,Linux 将中断处理过程分成了两个阶段,也就是上半部和下半部:

  • 上半部用来快速处理中断,它在中断禁止模式下运行,主要处理跟硬件紧密相关的或时间敏感的工作。
  • 下半部用来延迟处理上半部未完成的工作,通常以内核线程的方式运行
    比如说前面取外卖的例子,上半部就是你接听电话,告诉配送员你已经知道了,其他事儿见面再说,然后电话就可以挂断了;下半部才是取外卖的动作,以及见面后商量发票处理的动作。

这样,第一个配送员不会占用你太多时间,当第二个配送员过来时,照样能正常打通你的电话。

除了取外卖,我再举个最常见的网卡接收数据包的例子,让你更好地理解。

网卡接收到数据包后,会通过硬件中断的方式,通知内核有新的数据到了。这时,内核就应该调用中断处理程序来响应它。你可以自己先想一下,这种情况下的上半部和下半部分别负责什么工作呢?

对上半部来说,既然是快速处理,其实就是要把网卡的数据读到内存中,然后更新一下硬件寄存器的状态(表示数据已经读好了),最后再发送一个软中断信号,通知下半部做进一步的处理。

而下半部被软中断信号唤醒后,需要从内存中找到网络数据,再按照网络协议栈,对数据进行逐层解析和处理,直到把它送给应用程序。

所以,这两个阶段你也可以这样理解:

  • 上半部直接处理硬件请求,也就是我们常说的硬中断,特点是快速执行;
  • 而下半部则是由内核触发,也就是我们常说的软中断,特点是延迟执行。

实际上,上半部会打断 CPU 正在执行的任务,然后立即执行中断处理程序。而下半部以内核线程的方式执行,并且每个 CPU 都对应一个软中断内核线程,名字为 “ksoftirqd/CPU 编号”,比如说, 0 号 CPU 对应的软中断内核线程的名字就是 ksoftirqd/0。

不过要注意的是,软中断不只包括了刚刚所讲的硬件设备中断处理程序的下半部,一些内核自定义的事件也属于软中断,比如内核调度和 RCU 锁(Read-Copy Update 的缩写,RCU 是 Linux 内核中最常用的锁之一)等。

3.查看软中断和内核线程

前面提到过的 proc 文件系统。它是一种内核空间和用户空间进行通信的机制,可以用来查看内核的数据结构,或者用来动态修改内核的配置。其中:

  • /proc/softirqs 提供了软中断的运行情况;
  • /proc/interrupts 提供了硬中断的运行情况。

运行下面的命令,查看 /proc/softirqs 文件的内容,你就可以看到各种类型软中断在不同 CPU 上的累积运行次数:

$ cat /proc/softirqs
                    
CPU0       CPU1
          
HI:         
0         
0
       
TIMER:    
811613   
1972736
      
NET_TX:        
49         
7
      
NET_RX:   
1136736   
1506885
       
BLOCK:         
0         
0
    
IRQ_POLL:         
0         
0
     
TASKLET:    
304787      
3691
       
SCHED:    
689718   
1897539
     
HRTIMER:         
0         
0
         
RCU:   
1330771   
1354737

在查看 /proc/softirqs 文件内容时,你要特别注意以下这两点。

第一,要注意软中断的类型,也就是这个界面中第一列的内容。从第一列你可以看到,软中断包括了 10 个类别,分别对应不同的工作类型。比如 NET_RX 表示网络接收中断,而 NET_TX 表示网络发送中断。

第二,要注意同一种软中断在不同 CPU 上的分布情况,也就是同一行的内容。正常情况下,同一种中断在不同 CPU 上的累积次数应该差不多。比如这个界面中,NET_RX 在 CPU0 和 CPU1 上的中断次数基本是同一个数量级,相差不大。

不过你可能发现,TASKLET 在不同 CPU 上的分布并不均匀。TASKLET 是最常用的软中断实现机制,每个 TASKLET 只运行一次就会结束 ,并且只在调用它的函数所在的 CPU 上运行。

因此,使用 TASKLET 特别简便,当然也会存在一些问题,比如说由于只在一个 CPU 上运行导致的调度不均衡,再比如因为不能在多个 CPU 上并行运行带来了性能限制。

另外,软中断实际上是以内核线程的方式运行的,每个 CPU 都对应一个软中断内核线程,这个软中断内核线程就叫做 ksoftirqd/CPU 编号。那要怎么查看这些线程的运行状况呢?

其实用 ps 命令就可以做到,比如执行下面的指令:

$ ps aux | grep softirq
root        
7 
0.0 
0.0     
0    
0
?        S    Oct10  
0
:
01
[ksoftirqd/
0
]
root       
16 
0.0 
0.0     
0    
0
?        S    Oct10  
0
:
01
[ksoftirqd/
1
]

注意,这些线程的名字外面都有中括号,这说明 ps 无法获取它们的命令行参数(cmline)。一般来说,ps 的输出中,名字括在中括号里的,一般都是内核线程。

小结:

Linux 中的中断处理程序分为上半部和下半部:

  • 上半部对应硬件中断,用来快速处理中断。
  • 下半部对应软中断,用来异步处理上半部未完成的工作。

6.套路总结篇

6.1cpu使用率高,但是却找不到CPU高的应用:

(1)使用top查看各个CPU的使用情况,如果找不到CPU使用高的应用;

(2)继续使用pidstat可以查看每个进程的CPU使用情况;
(3)使用pidstat还是找不到CPU使用高的进程,可以再次观察top 里面的信息,查看有几个正在running的进程,如果running的进程数不符合的情况下,再次使用pidstat -p 进程号 查看每个正在running的进行的CPU使用情况;
(4)如果根据第三步找不到running进程的CPU使用情况,可以交叉使用其他的工具查看一下:ps aux | grep 24344,如果还是查看不到CPU的使用情况,那么要查看一下这个进程是不是没有了。如果查看到该进程还有,但是pid在改变,用 pstree 就可以用树状形式显示所有进程之间的关系:pstree | grep 进程的名字 。还可以用perf record -g 观察一会儿,然后用perf report 来试着查找具体导致性能问题的函数;
(5)execsnoop 就是一个专为短时进程设计的工具,用 execsnoop 监控上述案例,就可以直接得到 stress 进程的父进程 PID 以及它的命令行参数,并可以发现大量的 stress 进程在不停启动。

6.2cpu使用率100%,该怎么办?

(1)使用perf top ,可以实时查看占用CPU最多的进程和函数;

(2)使用perf record -g 和perf report 查看分析性能问题;

6.3系统中出现大量不可中断进程和僵尸进程怎么办?

使用top 查看进行的状态,D状态为不可中断进程,可能会导致I/O升高,会导致负载升高。Z状态为僵尸进行,进行结束没有被父进程回收。

iowait分析:使用dstat 1 10 ,观察CPU和I/O的使用情况;
(1)从top命令中找到D状态的进程pid,然后使用:pidstat -d -p pid 1 3 查看I/O读写情况
(2)如果没有发现异常情况,继续使用pidstat 去掉进程号,pidstat -d 1 20 来观察所有进程的I/O使用情况,找到具体导致I/O问题的进程;
(3)找到I/O问题的进程之后,使用strace -p pid 进行跟踪进程系统调用;如果没有跟踪到,看一下进程是否变成了Z状态的僵尸进程;
(4)进一步使用perf record -g ,等待一会儿之后,使用perf report 定位到我们发现的僵尸进程,按回车键展开调用栈,找到导致I/O的函数;
僵尸进程分析:先找到僵尸进程的父进程,然后在父进程里解决。
(1)使用命令:pstree -aps pid 找到父进程,查看父进程的代码;

6.4.软中断 CPU 使用率过高,该怎么办?

(1)使用top查看CPU的使用情况,如果各个情况都不高,看不出什么问题,查看软中断是不是使用了主要cpu;

  (2) 使用watch -d cat /proc/softirqs 查看文件内容的变化情况,查看NET_RX,也就是网络数据包接收软中断的变化速率最快。就从网络接收的软中断着手;
(3)使用sar -n DEV 1 查看网络收发情况;
   (4)然后分析网络帧;

6.5 当平均负载高于CPU数量70%的时候,应该分析负载高的问题;

CPU密集型:

(1)使用uptime 查看平均负载;
(2)使用mpstat 查看CPU使用率的变化情况;
(3)使用pidstat -u 5 1 可以找到CPU使用高的进程;
I/O密集型:
(1)watch -d uptime 查看平均负载的变化情况;
(2)mpstat -p ALL 5 1 查看CPU使用率变化情况,查看iowait 变化是否高;
(3)使用pidstat -u 5 1 查看到底是哪个进程导致iowait升高;
大量进程场景:
(1)uptime 查看平均负载;
(2)pidstat -u 5 1查看进程情况;
(3)查看是否是大量超出CPU进程在运行导致CPU过载;

6.6 大量CPU上下文切换;

(1)vmstat 常用来分析CPU上下文切换和中断次数;

(2)pidstat -w 5 可以查看每个进程上下文切换的情况;
(3)pidstat -wt 1 表示输出线程上下文切换的指标
(4)watch -d cat /proc/interrupts 观察中断变化情况;

6.7 CPU 性能分析的思路图谱

 

这张图里,列出了 top、vmstat 和 pidstat分别提供的重要的 CPU 指标,并用虚线表示关联关系,对应出了性能分析下一步的方向。

通过这张图你可以发现,这三个命令,几乎包含了所有重要的 CPU 性能指标,比如:

  • 从 top 的输出可以得到各种 CPU 使用率以及僵尸进程和平均负载等信息。
  • 从 vmstat 的输出可以得到上下文切换次数、中断次数、运行状态和不可中断状态的进程数。
  • 从 pidstat 的输出可以得到进程的用户 CPU 使用率、系统 CPU 使用率、以及自愿上下文切换和非自愿上下文切换情况。

另外,这三个工具输出的很多指标是相互关联的,用虚线表示了它们的关联关系,举几个例子你可能会更容易理解。

第一个例子,pidstat 输出的进程用户 CPU 使用率升高,会导致 top 输出的用户 CPU 使用率升高。所以,当发现 top 输出的用户 CPU 使用率有问题时,可以跟 pidstat 的输出做对比,观察是否是某个进程导致的问题。
而找出导致性能问题的进程后,就要用进程分析工具来分析进程的行程的行为,比如使用 strace 分析系统调用情况,以及使用perf 分析调用链中各级函数的执行情况。
第二个例子,top 输出的平均负载升高,可以跟 vmstat输出的运行状态和不可中断状态的进程数做对比,观察是哪种进程导致的负载升高。

  • 如果是不可中断进程数增多了,那么就需要做 I/O 的分析,也就是用 dstat 或 sar 等工具,进一步分析 I/O的情况。
  • 如果是运行状态进程数增多了,那就需要回到 top 和 pidstat,找出这些处于运行状态的到底是什么进程,然后再用进程分析工具,做进一步分析。

当发现 top 输出的软中断 CPU 使用率升高时,可以查看 /proc/softirqs 文件中各种类型软中断的变化情况,确定到底是哪种软中断出的问题。比如,发现是网络接收中断导致的问题,那就可以继续用网络分析工具 sar 和 tcpdump 来分析。

 

转载于:https://www.cnblogs.com/summerxye/p/11114368.html

你可能感兴趣的文章
VBScript:写excel的例子
查看>>
TYVJ P1077 有理逼近 Label:坑,tle的好帮手 不懂
查看>>
面试题:缓存Redis与Memcached的比较 有用
查看>>
通过UIWebView加载读取本地文件
查看>>
由于缺少证书链,导致Android手机提示网站不安全
查看>>
EXCEL自动撤销合并单元格并填充相应内容(转帖)
查看>>
Python3学习笔记10-条件控制
查看>>
Nginx 1.2.6 稳定版发布
查看>>
黄聪:如何使用CodeSmith批量生成代码(原创系列教程)
查看>>
HDOJ---1421 搬寝室[DP]
查看>>
熬过了互联网“寒冬”,接下来的金三银四你该怎么面试进BAT?
查看>>
JS 中的== 与 ===
查看>>
ES6 - 收藏集 - 掘金
查看>>
13.11. this is incompatible with sql_mode=only_full_group_by
查看>>
Python Module_openpyxl_处理Excel表格
查看>>
css动画实现div内图片逆时针旋转
查看>>
CSS的工作过程
查看>>
为什么码农要了解业务?
查看>>
微软整合实验(七):布署Exchange2010 Mailbox高可用(DAG)
查看>>
ntp 时间服务器
查看>>