项目压测相关

news2025/2/24 22:21:31

几个重要指标的关系
QPS= 并发数/平均响应时间
并发数 = QPS*平均响应时间
也就是说,并发连接数代表服务器抗压能力,接收连接的能力。qps代表在相同的并发数下,服务器处理的速度,响应时间越短,那么qps就越大。
不是说并发越多,qps越大,qps可能会在一个合适并发数,才会表现最大,就是每秒处理请求最多。

先学几个压测的工具。webbench,ab, wrk压测

webbench的标准测试可以向我们展示服务器的两项内容:每秒钟相应请求数(qps)和每秒钟传输数据量。webbench不但能具有标准静态页面的测试能力,还能对动态页面(ASP,PHP,JAVA,CGI)进 行测试的能力。
它的原理就是fork很多子进程,子进程随机选择ip+port,对你的网站发起连接,并发数,请求次数,持续时间自己设定。最后把结果汇总到父进程。
Webbench最多可以模拟3万个并发连接去测试网站的负载能力。

WebBench安装
首先下载 webbench脚本 http://home.tiscali.cz/cz210552/distfiles/webbench-1.5.tar.gz(或者去github下载)
解压webbench tar xvzf webbench-1.5.tar.gz
进入 webbench 目录
切换 root帐号:su root
安装 make && make install
测试命令
webbench -c 300 -t 60 http://test.domain.com/phpinfo.php
webbench -c 并发数 -t 运行测试时间 URL
就相当于向该网站发送100个连接即线程请求,持续60s。

会出现如下结果

Webbench - Simple Web Benchmark 1.5
Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.

Benchmarking: GET http://test.domain.com/phpinfo.php
300 clients, running 60 sec.

Speed=24525 pages/min, 20794612 bytes/sec.
Requests: 24525 susceed, 0 failed.

每秒钟响应请求数(qps):24525 pages/min,每秒钟传输数据量20794612 bytes/sec.
返回数:24525次返回成功,0次返回失败

并发数量改成1000,
Speed=24920 pages/min, 21037312 bytes/sec.
Requests: 24833 susceed, 87 failed.

说明超负荷了,有失败的请求了。

压测遇到的问题
1、muduo并发数太少?
在muduo库测试的时候并发1000就出现failed问题,这不正常。按理说它10k都没问题的。
因为muduo库的logging做的确实很好 出问题了 马上就会以 LOG_ERRNO显示出来 我就发现是 Acceptor accept出现了问题 而显示的原因是OPEN FILE TOO MUCH …
之后通过top lsof看了看 发现cpu占比也是正常的 只跑到了45% 说明负荷也不大啊 lsof之后看了看文件描述符的占用情况 就发现 只开到了1024… 终于发现问题了
原来是linux默认只允许一个进程打开1024个文件描述符 我就说什么情况… 对于一个c1k1000并发连接的服务器而言 怎么可能是足够的…
下面是单次修改 file_open参数的方法 暂时我还不知道怎么永久修改

1、sudo vim /etc/security/limits.conf
这里的话 在最底部增加以下两行即可(进程可打开最大文件描述符数目65536)
* soft nofile 65536
* hard nofile 65536

2、ulimit -n 65536(设置目前用户的最大文件描述符数目 重启后重置为默认1024)
3、ulimit -n或者ulimit -a(查看当前目前最大可开启文件描述符数目)

muduo短连接应该31000qps左右

前面这个问题的解决要知道下面的知识
并发连接数受哪些因素影响?
首先肯定本质是受硬件影响。对于长连接来说,并发数跟承载数量有关,也就是线程数量有关,理论上,创建的线程越多,并发数越大。但是线程创建又受到内存影响,线程会占用内存空间,对于4个G的内存,几百个线程就满了。实际上,线程不可能创建这么多,对于计算密集型任务忽略IO,线程数和CPU核数一致就可以了,目的是充分利用CPU;对于IO密集型任务,线程数=核数(1+IO/CPU),线程太多反而容易引起线程频繁切换导致CPU利用率变低。除了CPU核数外,还有网路带宽的影响,这个一般成为瓶颈。
在排除硬件影响后,还有几个特殊的因素需要考虑。第一就是可以提供的文件描述符数量,一个文件描述符才能提供一个TCP连接,进程能打开的文件描述符默认为1024,这当然会影响并发连接数,最多只能连接1000左右,因为系统进程本身就要用掉一些文件描述符。所以要记得修改这个默认数值。
第三就是,有没有可能文件描述符以及其他资源等打开忘记关闭了造成内存泄漏,这会导致你的服务器在几十秒内内存爆掉,每次都用新的文件描述符,直接死机。内存占用率是越来越高 到后面直接被爆掉 进程被杀死。(解决办法,智能指针,怎么用智能指针解决内存泄露?

2、内存占用越来越大,用智能指针解决内存泄露,回收文件描述符
可以用top查看。

3、主线程CPU使用率过高且客户端很多连接超时(没有log的情况下),而子线程很低
并发1000,按理说不应该有这么高的CPU使用率,正常应该,30左右。
问题出现在了listen的第二个参数 backlog改成几百就可以了。
试想下1W个并发,connect的时候,队列满了之后,服务器就不理会客户的connect,客户只能再次尝试,如果碰巧这时候队列还是满的。那么就再次尝试,如果命真的那么差。。估计挂掉之前都连不上,就超时了!!!!因为客户端不断尝试,那么就会不断和服务器发起三次握手的过程,服务器就会忙于和它建立握手,发送syn+ack等,所以cpu资源使用很多。
联系一些很多DDos攻击,就是一些半连接攻击或者全连接攻击,半连接攻击一些虚拟的ip来访问服务器,建立三次握手,但是最后一次不回复ack,那么就会存在半连接队列,让服务器瘫痪。
全连接就是建立三次握手,但不做事,一直在握手,也会导致服务器内存和CPU资源瘫痪。

我当时设置的backlog就是5。因为很多书上就是5,我认为这是一个比较好的值,就跟vector扩容为什么在1.5-2倍好。
listen(n)传入的值, n表示的是服务器拒绝(超过限制数量的)连接之前,操作系统可以挂起的最大连接数量。n也可以看作是"排队的数量"
TCP有如下两个队列:
SYN队列(半连接队列):当服务器端收到客户端的SYN报文时,会响应SYN/ACK报文,然后连接就会进入SYN RECEIVED状态,处于SYN RECEIVED状态的连接被添加到SYN队列,并且当它们的状态改变为ESTABLISHED时,即当接收到3次握手中的ACK分组时,将它们移动到accept队列。SYN队列的大小由内核参数/proc/sys/net/ipv4/tcp_max_syn_backlog设置。
accept队列(完全连接队列):accept队列存放的是已经完成TCP三次握手的连接,而accept系统调用只是简单地从accept队列中取出连接而已,并不是调用accept函数才会完成TCP三次握手,accept队列的大小可以通过listen函数的第二个参数控制。

在这里插入图片描述

4.优化工作线程,发现和muduo的qps差16%左右,工作线程cpu使用率高10%左右。
有没有可能是写工作业务代码解析http的时候(http echo),比较复杂,可以优化?协议解析?

5.开始超越?
分析瓶颈,然后自己的设计,线程池工作队列处理部分?协程部分? ET模式?

6 长连接短连接怎么测试?对压测结果影响的意义?
1000个并发数

服务器短连接QPS长连接QPS
WebServer126798335338
Muduo88430358302

可以看出,长连接下的qps是短连接的3到四倍左右,因为没有了tcp连接建立和断开的开销,不需要频繁accept和shutdown\close等系统调用,也不需要频繁建立和销毁对应的结构体。
之所以可以超越muduo,是因为采用了ET模式。muduo是水平触发,et模式适用于高并发短连接的场景。

水平触发:socket接收缓冲区不为空,有数据可读,读事件一直触发。只要可读,就一直触发读事件,只要可写,就一直触发写事件。边缘触发:从不可读变为可读,从可读变为不可读,从不可写变为可写,从可写变为不可写,都只触发一次。当使用ET做触发模式时,我们通常使用while()循环来将sockfd的数据全部读出来
水平触发:

1.从accept成功之后,可写事件就会一直触发,直到发送缓冲区满了。对方给你发送了数据,只要你的接收缓冲区还有数据没取完就会一直触发可读事件。
2.当对方断开连接,不管是主动断开还是异常断开,都会触发可读可写事件。为什么?因为你recv和send的时候都会给你返回(read主动断开0,异常断开-1,write返回-1,触发SIGPIPE)。

int number = epoll_wait( epollfd, events, MAX_EVENT_NUMBER, -1 );//通过epoll_wait监听到epoll事件响应,events中会保存响应的事件队列
sockfd = events[i].data.fd;//从事件队列中取出对应的文件描述符fd
n = recv(sockfd , buff, MAXLNE, 0);//通过recv将sockfd缓冲区的数据接收进buff中

int number = epoll_wait( epollfd, events, MAX_EVENT_NUMBER, -1 );//通过epoll_wait监听到epoll事件响应,events中会保存响应的事件队列
sockfd = events[i].data.fd;//从事件队列中取出对应的文件描述符fd
m_read_idx = 0;//记录一次读数据后的位置索引
while(true) {//
   // 从buff + m_read_idx索引出开始保存数据
    n = recv(sockfd , buff + m_read_idx, MAXLNE, 0 );//通过recv将sockfd缓冲区的数据接收进buff中
    if (n == -1) {
        if( errno == EAGAIN || errno == EWOULDBLOCK ) {
            // 没有数据
            break;
        } 
    } else if (n == 0) {   // 对方关闭连接
		//close(sockfd);
		break;
    }
    m_read_idx += n;
}

水平触发虽然编码简单,但是重复地事件触发会影响高并发服务器地性能,因为epoll_wait返回监控事件涉及到系统调用,需要用户态-内核态的转换。特别是对于高并发短连接,会频繁返回由于没有读完数据,并且短连接频繁断开链接也会触发可读可写事件,让epoll返回。
所以看到,短连接1000并发下,ET模式比LT模式性能高,长连接的话相差不大。
ET真的比LT快吗?
首先,如果并发量不大,或者说读取的数据都是小数据,按理说应该没有区别的;如果是大量数据,LT就会产生更多无畏的系统调用,慢一点;
从ET的处理过程中可以看到,ET的要求是需要一直读写,直到返回EAGAIN,否则就会遗漏事件。而LT的处理过程中,直到返回EAGAIN不是硬性要求,但通常的处理过程都会读写直到返回EAGAIN,但LT比ET多了一个开关EPOLLOUT事件的步骤
其次,如果server的响应通常较小,不会触发EPOLLOUT,那么适合使用LT,例如redis等。而nginx作为高性能的通用服务器,网络流量可以跑满达到1G,这种情况下很容易触发EPOLLOUT,则使用ET。

综上,对于高并发大数据肯定是ET好,小数据的话ET稍微快一点,原因是如果写出1m大小数据,一次写不完,LT会开启EPOLLOUT事件,如果写完关闭;ET是一直写,直到写完或者返回EGAIN,如果写完是不开启EPOLLOUT.

**如何通过压测等其他方法找到性能瓶颈?**要有自己的思考
文件描述符没有及时关闭?
处理逻辑问题?

总结:

1、遇到问题,1000就会有失败的连接了。第一,文件描述符限制问题,1024修改,发现还是不行,原来是ET模式导致accept只会发一次通知,由于并发量很大,所以没有及时加到epoll里面去,那么很多连接没办法及时加就会超时,导致连接失败;办法就是accept用while包一层,直到没有再回去。而且不仅仅是accept,对于read,write都要保证一次搞完不然数据不对的。所以我直接用LT,发现效率更高一点。
所以发现其实并不是ET比LT高效,得看什么场景。
首先对于读,其实没有什么影响,因为高并发下epollwait返回本来就频繁,不会因为你没读完就多返回很多次。实际上影响最大的是write.原因是,LT写缓冲区没满就会继续写。所以当你数据写完后返回eagin,这时候必须关闭一下epoll_ctl关闭一下写事件,不然写会一直触发,没有机会返回epollwait监听,回去后再加上。而ctl是系统调用,就会多了几次系统调用。而数据量越大,中间出错的概率高,所以这时候返回是要继续写的,LT就比较适合了。反而ET一次性读完会导致其他fd饥饿。
比如redis用的就是LT,nignx是ET.潜在的原因是redis数据量小,而nignx很有可能数据跑到1G这么多,数据越多,其实主要影响是在

  1. backlog问题。
    主线程CPU使用率过高且客户端很多连接超时(没有log的情况下),而子线程很低**
    并发1000,按理说不应该有这么高的CPU使用率,正常应该,30左右。子线程很低说明请求很少,因为客户端很多没有连接上。
    这里我开始怀疑我的协程是不是有问题,但是按理说也只是多了一次子协程多主协程的切换,最多就寄存器换几个值,怎么可能出现CPU利用率这么高而且连接不上?
    这里卡了很久。 后来发现一个点就是listen的第二个参数

问题出现在了listen的第二个参数 backlog改成几百582就可以了。
试想下1W个并发,connect的时候,队列满了之后,服务器就不理会客户的connect,客户只能再次尝试,如果碰巧这时候队列还是满的。那么就再次尝试,如果命真的那么差。。估计挂掉之前都连不上,就超时了!!!!因为客户端不断尝试,那么就会不断和服务器发起三次握手的过程,服务器就会忙于和它建立握手,发送syn+ack等,所以cpu资源使用很多。
联系一些很多DDos攻击,就是一些半连接攻击或者全连接攻击,半连接攻击一些虚拟的ip来访问服务器,建立三次握手,但是最后一次不回复ack,那么就会存在半连接队列,让服务器瘫痪。
全连接就是建立三次握手,但不做事,一直在握手,也会导致服务器内存和CPU资源瘫痪。
我当时设置的backlog就是5。因为很多书上就是5,我认为这是一个比较好的值,就跟vector扩容为什么在1.5-2倍好。
listen(n)传入的值, n表示的是服务器拒绝(超过限制数量的)连接之前,操作系统可以挂起的最大连接数量。n也可以看作是"排队的数量"
TCP有如下两个队列:
SYN队列(半连接队列):当服务器端收到客户端的SYN报文时,会响应SYN/ACK报文,然后连接就会进入SYN RECEIVED状态,处于SYN RECEIVED状态的连接被添加到SYN队列,并且当它们的状态改变为ESTABLISHED时,即当接收到3次握手中的ACK分组时,将它们移动到accept队列。SYN队列的大小由内核参数/proc/sys/net/ipv4/tcp_max_syn_backlog设置。
accept队列(完全连接队列):accept队列存放的是已经完成TCP三次握手的连接,而accept系统调用只是简单地从accept队列中取出连接而已,并不是调用accept函数才会完成TCP三次握手,accept队列的大小可以通过listen函数的第二个参数控制。

这里改完之后就正常了。
大概有八万左右的,和muduo差不多。或许不用协程会更高一点。

3、找瓶颈。
分析过程。我发现了一个问题,就是10000连接的时候子线程的CPU使用率,包括主线程的使用率都不是很高(70左右)?按理说,
我这种主从reactor模型在这么大的并发量,主线程,子线程CPU使用率应该跑满的,因为我没有连接数据库缓存rpc什么的,子线程获取任务直接发送数据了,不会有这么多的阻塞等待;
我发现了,问题就出在任务队列。需要加锁,而且是锁住整个队列,出队入队是串行化的。这样就会阻塞住。(出队入队是比较耗时的,要找到坐标。因为存在伪共享的问题,head,tail会互相影响,导致缓存行失效,每次都从内存取,需要几十到几百个时钟周期,并且pop要删除任务,删除操作需要空闲链表管理)。 所以我们采用的是一个环形的无锁消息队列。预先分配一个环形队列…
搞完后,发现cpu使用率增加了,大概92。 qps明显提高了40左右

top可以查看动态的CPU使用率,首先一个总体的。(进程数、CPU使用率、内存使用情况,SWAP分区情况) 然后下面是进程列表的具体情况;(很有可能进程超过100%,因为开启了多线程,NUMA架构,每个CPU加起来)
但是我们要查的是线程的使用情况。
top -H -p 15736 先看进程,然后-H参数可以看里面线程的CPU使用情况。

4 未来展望
C10K-C10M
首先硬件不是问题。核心是软件。(阻塞不仅仅在IO,还可能在数据拷贝,地址翻译,内存管理,数据处理)
问题核心:不要让OS内核执行所有繁重的任务:将数据包处理、数据拷贝,内存管理、处理器调度,地址翻译等任务从内核转移到应用程序高效地完成,让诸如Linux这样的OS只处理控制层,数据层完全交给应用程序来处理。

1、要知道linux内核一开始就是一个分时系统,最重要的是保证公平性,CFS算法。而我们的实际任务可能会有差别,所以最好把调度让应用程序完成,减轻内核调度的负担以及无意义的调度;
2、核绑定,任务可能会在不同的CPU核上运行,尤其现在是NUMA架构,会导致上下文的切换,以及cache命中率的问题;
3、数据包直接和应用层交互,Linux协议栈是复杂和繁琐的,数据包经过它无非会导致性能的巨大下降,并且会占用大量的内存资源。比如DPDK的网卡驱动就是在应用层,数据不经过内核。(当然发给自己的数据包肯定要经过内核)
4、大页机制的开启,减少地址转换开销。(4kb-2mb)
5、零拷贝技术(kafka),sendfile。直接在内核的page cache利用内存映射,然后记录偏移量和总量,读的时候直接读不要复制到socket内核缓存。(就比如我们线程池处理完发回客户端就要经过这些四次拷贝,可能零拷贝之后CPU利用率更高了)

2.1. HTTP echo 测试 QPS
测试机配置信息:Centos虚拟机,内存6G,CPU为4核

测试工具:wrk: https://github.com/wg/wrk.git

部署信息:wrk 与 TinyRPC 服务部署在同一台虚拟机上, 关闭 TinyRPC 日志

测试命令:

// -c 为并发连接数,按照表格数据依次修改
wrk -c 1000 -t 8 -d 30 --latency 'http://127.0.0.1:19999/qps?id=1'

测试结果:

QPSWRK 并发连接 1000WRK 并发连接 2000WRK 并发连接 5000WRK 并发连接 10000
IO线程数为 127000 QPS26000 QPS20000 QPS20000 QPS
IO线程数为 4140000 QPS130000 QPS123000 QPS118000 QPS
IO线程数为 8135000 QPS120000 QPS100000 QPS100000 QPS
IO线程数为 16125000 QPS127000 QPS123000 QPS118000 QPS





本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/568237.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Unity Lightmapping Setting

如下图: Lightmapper: 使用什么硬件或算法渲染 Progressive CPU、Progressive GPU、Enlighten(新的算放目前用的比较少) 此数值会被用于分别乘以Direct Samples,Indirect Samples和Environment Samples这三个数值。这三个数值会被应用于…

【Netty】Netty 如何实现零拷贝(八)

文章目录 前言一、Java 实现零拷贝1.1 Java提供 mmap/write 方式1.2 Java 提供 sendfile 方式 二、Netty 实现零拷贝2.1 CompositeByteBuf 方式2.1 wrap 方式2.3 slice 方式2.4 FileRegion 方式 总结 前言 回顾Netty系列文章: Netty 概述(一&#xff0…

李沐多模态串讲笔记

李沐多模态串讲笔记 0.来源1.回顾1.1 ViLT回顾1.2 Clip回顾1.3回顾小结 2.ALBEF2.1摘要2.2主体方法部分2.2.1模型设计2.2.2目标函数2.2.3momentum distillation 动量蒸馏 2.3下游任务和实验结果 3.VLMo3.1论文贡献3.2研究动机3.3主体方法部分3.3.1模型设计3.3.2分阶段的训练策略…

Android 12 通知样式整理

目录 0. 📂 前言 1. 🔱 通知样式总览 2. ⚛️ 通知样式详解 2.1 Simple Notifiaction 2.2 Action Notifiaction 2.3 Remote Input Notifiaction 2.4 Big Picture Notifiaction 2.5 Big Text Notifiaction 2.6 Inbox Notifiaction 2.7 Media No…

Cobalt Strike工具基本使用

Cobalt Strike 安装启动启动server端启动client目标机器连接 工具基使用用户驱动攻击屏幕截图进程列表键盘记录文件管理远程vnc远程代理端口扫描 生成后门被攻击者运行后门文件后查看结果 钓鱼攻击信息收集网站克隆文件下载 安装 网盘地址:链接:https:/…

AntDB-S流式数据库体验

本文作者:彭冲老师,上一篇彭老师体验了亚信刚发布的社区版AntDB-T数据库,文章如下: AntDB-T交易型数据库体验 本文继续体验AntDB-S流式数据库的,AntDB-S目前还未开放社区版,可以联系AntDB小助手进行体验。…

电压放大器的主要指标有哪些方面

电压放大器是电子电路中常用的器件,在选择和评估电压放大器时,需要考虑以下几个主要指标: 输入电阻(Input Resistor):输入电阻是指放大器输入端的电阻值,它反映了放大器将输入信号转换成输出信号…

亚马逊,速卖通,国际站卖家在做测评时如何将风险降到最低呢?

测评是亚马逊卖家提升产品可信度和销售表现的重要手段 现在的测评市场遭到卖家们的极力吐槽,想要找到靠谱的资源也越来越难。据了解,去年很多骗子,中介都涌进测评市场,随意报价,导致整个市场鱼龙混杂,卖家…

MyBatis源码学习四之二级缓存

MyBatis源码学习四之二级缓存 MyBatis的缓存使用的也比较多,而缓存的都实现了一个父类的接口Cache。 一、加载缓存类PerputualCache public static void main(String[] args) {InputStream inputStream null;try {inputStream Resources.getResourceAsStream(&q…

NRK3303语音识别芯片在照明灯上的运用,一款可分布式语音IC方案

随着科技的不断进步,人们对于家居生活中的照明设备的要求也逐渐提高。传统的照明方式已经不能满足人们对智能家居的需求,我们需要更加智能、易于操作、高效节能的智能化照明系统。因此,智能照明应运而生,为我们提供了更加智能化、…

倍福触摸屏维修控制面板CP6606-0001-0020

适合控制柜安装的CP6600和CP6606面板型PC,适用于机械制造和设备工程等各种应用;可以安装TwinCAT自动化软件和 Windows Embedded操作系统,用作单独的控制器,也可以用作远程桌面显示器。 倍福触摸屏常见故障分类: 1、磨…

linux学习[11]磁盘与文件系统(2):lsblkblkidpartedfdiskgdiskmkfs

文章目录 前言:1. 磁盘容量1.1 lsblk1.2 blkid1.3 parted 2. 磁盘分区2.1 fdisk/gdisk2.2 磁盘分区实例参考: 3. 磁盘格式化3.1 mkfs.xfs3.2 mkfs.ext43.3 mkfs.vfat 总结: 前言: 写了VMware的磁盘扩容之后,磁盘分区格…

深度学习基础-卷积神经网络CNN+深度学习(无代码仅理解)

参考书籍:(找不到资源可以后台私信我) 《深度学习入门:基于Python的理论与实现 (斋藤康毅)》 CNN 概括 其中pooling层有时候会被省略,卷积层的输入输出图像称为特征图(feature map)&#xff0c…

多线程-Thread类的常用方法和生命周期

Thread类的常用结构 构造器 public Thread():分配一个新的线程对象。public Thread(String name):分配一个指定名字的新的线程对象。public Thread(Runnable target):指定创建线程的目标对象,它实现了Runnable接口中的run()方法。public Thread(Runnable target,S…

Python实现温度植被干旱指数(TVDI)的计算

前言 温度植被干旱指数(Temperature Vegetation Dryness Index,TVDI)是一种基于光学与热红外遥感通道数据进行植被覆盖区域表层土壤水分反演的方法。作为同时与归一化植被指数(NDVI)和地表温度(LST)相关的温度植被干旱指数(TVDI)可用于干旱监…

第二十五节:通信之WLAN(WiFi聚合)

欢迎大家一起学习探讨通信之WLAN。为了减少帧交互中额外资源占用开销,提高WiFi网络系统整体运行效率,802.11n协议引入定义了聚合功能。本节将基于协议定义内容和实例,详细分析“A-MSDU"和“A-MPDU”两种聚合功能。 关键字 S1G(Sub 1 GH…

linux0.12-10-6-tty_io.c

[539页] 10-6 tty_io.c程序 10-6-1 功能描述 每个tty设备有3个缓冲队列,分别是读缓冲队列(read_q)、写缓冲队列(write_q)和辅助缓冲队列(secondary),定义在tty_struct结构中(include/linux/tty.h)。 对于每个缓冲队列,读操作是从缓冲队列的…

数据可视化:部分整体类可视化图表大全

图表是处理数据的重要组成部分,因为它们是一种将大量数据压缩为易于理解的格式的方法。数据可视化可以让受众快速Get到重点。 数据可视化的图表类型极其丰富多样,而且每种都有不同的用例,通常,创建数据可视化最困难的部分是确定哪…

冯诺依曼体系结构详解

一.冯诺伊曼体系结构的概念: 约翰冯诺依曼(John von Neumann,1903.1.28-1957.2.8),美籍匈牙利数学家,计算机科学家,物理学家。是20世纪最重要的数学家之一,后来被称为计算机之父。 后…