计算机基础(中断、IO)

操作系统

设备交互

CPU 与 IO 设备交互过程
CPU 通过设备控制器(驱动?)与计算机外设进行交互。可以将控制器想象成编程语言中的接口,然后不同地计算机外设的控制器去实现这个接口,CPU 只需要调用接口而无需关注具体地实现,通过这种设计可以让 CPU 指令做得精简。

拓展:软件六大编程原则之一:依赖倒置原则:上层模块不应该依赖底层模块,它们都应该依赖于抽象;抽象不应该依赖于细节,细节应该依赖于抽象。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

中断

CPU 中断机制:键盘原理
在这里插入图片描述

DMA(Direct Memory Access)

将用户程序的数据源地址、数据目的地址以及数据长度一次性送给相应外设的 DMA 程序,从而减少 CPU 中断次数提高性能。

  1. 中断加 DMA 减少 CPU 开销

注意:DMA 只能完成内核与计算机外设之间的数据拷贝,内核态与用户态之间的数据拷贝还是需要 CPU 介入

系统调用

程序主要分为用户程序和操作系统程序两种,分别运行在用户空间和内核空间,为了安全以及保证硬件设备和操作系统的稳定性,只有操作系统程序才有权限访问硬件设备,所以应用程序只能通过系统调用/中断/异常三方式之一从用户态切换到内核态,经由操作系统程序完成与计算机外设的交互。

注:系统调用分类
在这里插入图片描述

  1. printf 的用户态与内核态切换动画演示
  2. 内核态 vs 用户态:通过内核态程序实现计算机资源的统一调度协调,从而让用户程序有条不紊地运行。
    在这里插入图片描述
  3. Linux 如何实现系统调用

32bit 操作系统的系统调用也是通过发起 ENTER_KERNEL 调用,发起中断指令 0x80 来实现的。
在这里插入图片描述
运行在用户态的函数通过 CPU 中的寄存器将函数执行的必要信息(系统调用号(哪个系统调用函数)、函数参数)传递给系统调用中断程序
在这里插入图片描述
系统中断程序运行过程:
在这里插入图片描述

64bit 操作系统的系统调用则直接通过 syscall 指令来实现的
在这里插入图片描述

I/O

同步阻塞

在 IO 连接建立后,对应的线程会被阻塞,直到收到数据后,该阻塞状态才会被解除。

  • 如果使用一个线程来监听连接,一个进程只能为一个客户提供服务;
  • 如果为每个连接单独分配一个线程可以解决一个进程维护多个连接的目的,但线程调度、上下文切换以及其占用的栈空间都可能成为瓶颈。
代码示例
#include <unistd.h>
#include <sys/socket.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <iostream>using namespace std;/** 1. 创建套接字* 2. 绑定地址信息* 3. 进行监听--(告诉OS内核可以接收客户端发送的新请求了并且监听新连接的到来)* 4. TCP三次握手建立连接----OS会自动进行,不需要我们进行控制* 5. 接收新连接* 6. 接收数据、发送数据* 7. 关闭套接字*/ int main()
{//1. 创建套接字int sockfd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);if(sockfd < 0){cout << "TCP socket failed" << endl;return 0;}//2.绑定地址信息struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(18989);addr.sin_addr.s_addr = inet_addr("0.0.0.0");int ret = bind(sockfd,(struct sockaddr *)&addr,sizeof(addr));if(ret < 0){cout << "bind failed" << endl;return 0;}//3.进行侦听(告诉OS内核可以与客户端建立连接了)//listen函数中blocklog参数,设定的是已完成三次握手并已建立连接的队列的容量ret = listen(sockfd,1);if(ret < 0){cout << "listen failed" << endl;return 0;}//4.接收新连接struct sockaddr_in client_addr;socklen_t socklen = sizeof(client_addr);int new_sockfd = accept(sockfd,(struct sockaddr *)&client_addr,&socklen);if(new_sockfd < 0){cout << "accept failed" << endl;return 0;}printf("accept success: %s:%d, and new_sockfd is %d\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port),new_sockfd);//5.接收和发送数据while(1){//这里接收数据和发送数据是没有顺序而言的//因为已经经过三次握手,客户端和服务端的连接以及建立成功了char buf[1024] = {0};ssize_t recv_size = recv(new_sockfd,buf,sizeof(buf)-1,0);if(recv_size < 0){cout << "recv failed" << endl;continue;}else if(recv_size == 0){cout << "Peer close" << endl;close(new_sockfd);close(sockfd);return 0;}cout << "accrpt data is : " << buf << endl;//发送数据memset(buf,'\0',sizeof(buf));sprintf(buf,"hello lient,i am server,i am %s:%d\n",inet_ntoa(addr.sin_addr),ntohs(addr.sin_port));ssize_t send_ret = send(new_sockfd,buf,strlen(buf),0); if(send_ret < 0){cout << "send failed" << endl;continue;}}close(sockfd);return 0;
}

可以看出socket 编程服务端核心步骤为:

  1. bind:绑定端口
  2. accept:等待客户端连接
  3. rev:接收客户端请求
  4. send:将数据响应给客户端
资料
  1. 动画演示 BIO 原理:socket 结构、进程切换、用户态与内核态的切换。
    在这里插入图片描述
  2. Socket 缓冲区

一个 socket,会带有两个缓冲区,一个用于发送,一个用于接收。因为这是个先进先出的结构,有时候也分别叫它们发送队列、接收队列。
在这里插入图片描述

同步非阻塞

I/O 是否阻塞,由这个连接对应的 fd 阻塞属性决定。
在这里插入图片描述
在 Linux 中,可以在创建 socket 时,直接将它设置为非阻塞模式 int socket (int __domain, int __type, int __protocol),将 __type 增加SOCK_NOBLOCK 就可以创建一个非阻塞的 socket,例如:int socket_fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);

异步

Reactor 与 Proactor 为什么性能高?

先来看看阻塞 I/O,当用户程序执行 read ,线程会被阻塞,一直等到内核数据准备好,并把数据从内核缓冲区拷贝到应用程序的缓冲区中,当拷贝过程完成,read 才会返回。

注意:阻塞等待的是「内核数据准备好」和「数据从内核态拷贝到用户态」这两个过程。非阻塞的 read 请求在数据未准备好的情况下立即返回,可以继续往下执行,此时应用程序不断轮询内核,直到数据准备好,内核将数据拷贝到应用程序缓冲区,read 调用才可以获取到结果。

将数据从内核缓冲区拷贝到用户程序空间是一个同步过程。因此,无论 read 和 send 是阻塞 I/O,还是非阻塞 I/O 都是同步调用。

异步 I/O 在「内核数据准备好」和「数据从内核态拷贝到用户态」这两个过程都不用等待。 当我们发起 aio_read (异步 I/O) 之后,就立即返回,内核自动将数据从内核空间拷贝到用户空间,这个拷贝过程是内核自动完成的,和前面的同步操作不一样,应用程序并不需要主动发起拷贝动作。

资料
  1. 动画演示 NIO 原理
    在 IO 连接建立后,对应的线程在未收到数据时不会被阻塞,程序员可以将该连接对应的 fd 用集合保存起来,后续逐次轮询,有数据时再从 fd 对应的连接中取出数据进行处理,达到一个线程可以处理多个网络连接的目的,从而提高效率。

在这里插入图片描述

多路复用

多路:指多个 Socket 连接,复用:使用同一个线程。

动图解释 select、poll、epoll 实现原理

select(man 2 select)

select 中定义的 fd_set 实际是一个 bitmap(默认长度为 1024 ,更改该长度需要修改内核代码然后重新编译),以文件描述符作为 bitmap 的索引设置值。内核会轮询集合中的 fd,当对应的 fd 的数据队列中有数据时,会将其对应的等待进程队列中的进程唤醒,并根据 fd 是否有数重新设置 bitmap 的值后从内核态重新返回到用户态,用户程序从 bitmap 有值的 fd 中读取数据。
在这里插入图片描述
总结:
在这里插入图片描述
使用:MySQL

其它
  1. 位图实现:通过 long 数组模拟而成,每个比特对应一个文件描述符数值。
    在这里插入图片描述通过在 Linux 上执行 man select 可以看到:

An fd_set is a fixed size buffer. Executing FD_CLR() or FD_SET() with a value of fd that is negative or is equal to or larger than FD_SETSIZE will result in undefined behavior. Moreover, POSIX requires fd to be a valid file descriptor.

FD_SETSIZE 在 sys/select.h 文件中的定义如下:

// include/uapi/linux/posix_types.h
#define __FD_SETSIZE    1024typedef struct {unsigned long fds_bits[__FD_SETSIZE / (8 * sizeof(long))];
} __kernel_fd_set;

可以看出 Linux 内核的宏限制了 fd_set 最多只支持1024。

注意:

  1. 在 Linux 中,文件描述符数值 0,1,2 已经被系统占用,分别表示为标准输入,标准输出和标准错误。
  2. select 不支持大于 1024 的文件描述符的监听。
  1. select 函数的参数 maxfd (最大文件描述)有什么作用?
    select 使用 1024 比特位图监测最多 1024 个文件描述符,然而实际的情况很少会到达1024文件描述符上限,使用 maxfd 可以避免每次都轮询 1024 个文件描述符,从而提高轮询效率。maxfd 通常设置为已打开最大文件描述符 +1,目的是为了保证位图中每个文件描述符都被轮询到。
  2. 优缺点
  • 优点:
    1. select 支持多种文件描述符类型,包括 socket、标准输入输出、管道、FIFO 等。
    2. select是跨平台的,可以在多种操作系统上使用。
  • 缺点:
    1. select 的效率不高,每次调用 select 都需要将所有托管的文件描述符从用户态复制到内核态,托管的文件描述符中有一个文件描述符事件就绪后,也会将所有托管的文件符从内核空间拷贝到用户空间,这个过程比较耗时。
    2. select返回后需要遍历所有的文件描述符,找到就绪的文件描述符,这个过程也比较耗时。
    3. select支持的文件描述符数量有限,需要保证放入 select 监听的文件描述符不大于 1024,否则程序会出现未知错误。
  1. select 为什么会有 1024 文件描述符限制?
    • select 采用轮询的方式获取读,写,异常事件,如果需要轮询的文件描述符比较多的话,select 执行效率会非常低。
poll(man 2 poll)

下图有些错误:revents 不只是一个状态标识 1,其值为可用的事件(比如 POLLIN)
在这里插入图片描述

注释:

  1. 最常用的网络事件为 EPOLLIN 和 EPOLLOUT,EPOLLIN 对应为有 socket 缓冲区数据可读(当又收到了对端的一些数据,就会触发;或者作为服务端时有连接连过来),EPOLLOUT 对应 socket 缓冲区可写。

总结:
在这里插入图片描述

epoll(extend poll:man 2 epoll_create)

可以通过红黑树以 O(log(n)) 的复杂度找到该 fd 对应的 epitem
在这里插入图片描述
注意:

  • 调用 epoll_ctl 函数将 fd 添加(EPOLL_CTL_ADD)到红黑树时,也会注册一个回调函数,该回调函数在该 fd 关注的事件发生时,会将其对应的 epitem 加入到数据就绪队列中。

红黑树排序规则 :
在这里插入图片描述
总结:
在这里插入图片描述
注意:

  • 由于需要在内核空间查找红黑树,所以实际的时间复杂度为 O(log(n)),这里的 O(1) 指,通过 epoll_wait 返回到用户空间的 epoll_event 数组都是有事件发生的 fd,所以无需像 select 或 poll 那样,在用户空间遍历 fd 集合(时间复杂度为 O(n))判断 fd 是否就绪(select 通过 FD_ISET 函数,poll 通过类似 pollfd.revents & POLLIN 运算)。
  • select、poll 在监听 fd 状态前,每次都需要全量的将需要监听的 fd 集合从用户态拷贝到内核态,在 fd 集合中有一个 fd 发生监听的事件时,也会全量的 fd 集合从内核态拷贝到用户态,这样是及其耗费资源与性能的。epoll 只有在调用 epoll_ctl 时,才会将 fd 从用户态拷贝到内核态,然后在内核态维护该 fd 集合构成的红黑树,在 fd 集合中有 fd 发生了监听的事件时,也只会返回这些发生了事件的 fd。
    在这里插入图片描述
思考
  1. 在并发量不高时,select、poll 通过轮询 fd 集合来判断 fd 是否已经就绪的效率也并不低,所以此时仍然可考虑使用 select 和 poll,但如果在高并发量情况下(比如 C10K),就需要用 epoll 模型,它的速度更快,开销更小。
  2. 红黑树 vs 哈希表

linux 内核提供的哈希表是 hlist,即采用拉链法解决哈希碰撞的方法。hlist 进行哈希查找是 O(1) 是建立在哈希映射到各个桶的概率一致,并保证现有元素比桶个数小于负载因子 α 后,在有足够多元素时可以认为每一个桶中元素的个数服从 π(α) 即泊松分布。然而,在某些极端的情况下(或者说哈希安全性被打破的情况下),某些桶内包含了更多的元素,某些元素的查找时间会远高于其它的,并且单依靠拉链法是无法解决这种退化情况的。在删除某些元素时需要找到对应的节点,也就是说,在扩容/缩容和删除某些节点时,其操作时间可能是不可控的。相比之下,红黑树的强约束就显得可控许多了。

  1. 相比 select、poll 只支持水平触发(LT:Level Triggered),epoll 还支持边缘触发(ET:Eage Triggered),两种触发模式的区别是啥?

水平触发和边缘触发通过 epoll_wait 函数的响应体现,示例。

  • LT:只要缓冲区有数据,epoll_wait 就会一直被触发,直到缓冲区为空;(有数据会连续触发)
  • ET:只有所监听的事件状态改变或者有事件发生时,epoll_wait 才会被触发;(有数据只触发一次)

Nginx ,除了 listenfd(网络服务器中一般涉及两类 sockfd:用于监听是否有连接请求的 listenfd;用于传输数据的 socket(accept 返回的 acceptfd)) 用水平触发之外,其它都是用的边缘触发。

  • 有一些解释是 listenfd 用水平触发,如果多个 client 同时连接进来,accept 一次只处理一个连接,为防止漏掉连接选择水平触发。
  1. 为什么 IO 多路复用要搭配非阻塞 IO?
    • 为什么 IO 多路复用要搭配非阻塞 IO?

    假如 socket 的读缓冲区中已有足够多的数据,需要调用三次 read 才能读取完。

    1. 非阻塞 I/O 的处理方式:循环的 read 或 accept,直到读完所有的数据(抛出 EWOULDBLOCK 异常)
    2. 阻塞 I/O 的处理方式:每次只能调用一次 read 或 accept,因为多路复用只会告诉你 fd 对应的 socket 可读了,但不会告诉你有多少的数据可读,所以在 handle_read/handle_accept 中只能 read/accept 一次,你无法知道下一次 read/accept 会不会发生阻塞。所以只能等 ioloop 的第二次循环,ioloop 告诉你 fd 可用后再继续调用 handle_read/handle_accept处理,然后再循环第三次。

      所以你会发现,阻塞方式稍不注意就会阻塞整个进程:多路复用只能知道有数据可读,但是不知道有多少数据可读,使用阻塞io,读了一次就不知道是否应该继续读,如果继续读,读到第四次就阻塞了。

零拷贝

资料
  1. 动画演示-传统网络读写过程:四次上下文切换,四次数据拷贝(两次 DMA 拷贝 + 两次 CPU 拷贝)
    在这里插入图片描述 动画图解 socket 缓冲区那些事:每个 socket 在内核态都有对应的读写缓冲区(readbuf、writebuf)
    在这里插入图片描述
    在这里插入图片描述

  2. 动画演示-MMAP + write 实现“零拷贝”:通过 mmap 建立了 PageCache 到用户进程的虚拟地址空间的映射,即用户进程可以直接通过 mmap 返回的 fd 直接读取 pagecache 对应的物理内存空间(四次上下文切换 + 三次数据拷贝(两次 DMA 拷贝 + 一次 CPU 拷贝))
    在这里插入图片描述

  3. 动画演示-sendfile 实现零拷贝:二次上下文切换 + 三次数据拷贝(两次 DMA 拷贝 + 一次 CPU 拷贝)
    在这里插入图片描述

注意:linux kernel 2.1 开始支持 sendfile

  1. 动画演示-sendfile + DMA gather copy 实现零拷贝:sendfile 利用 DMA 将文件内容拷贝到内核缓冲区(PageCache),然后将带有文件位置和长度信息的缓冲区描述添加到 socket 缓冲区(这一步不会将内核中的数据拷贝到 socket 缓冲区中),DMA 会直接将内核缓冲区的数据拷贝到网卡设备通过网络发送出去。(两次上下文切换 + 两次 DMA 拷贝)
    在这里插入图片描述

注意:linux kernel 2.4 才支持这种拷贝方式,并且需要硬件以及驱动程序的支持

  1. 动画演示-splice + DMA 实现零拷贝: splice 通过在 PageCache 和 Socket 缓冲区之间建立一个环型管道,这样DMA 可以直接通过 socket 缓冲区将 PageCache 中的数据拷贝到网卡设备(两次上下文切换 + 两次 DMA 拷贝)
    在这里插入图片描述

注意:linux kernel 2.6.17 才引入 splice。splice 利用 Linux 的管道缓冲区机制, 所以要求绑定的两端的描述中至少有一个为管道设备。

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

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

相关文章

如何使用生成式人工智能进行科学文献检索?

在学术写作过程中&#xff0c;查找文献是一个至关重要的步骤。文献检索不仅可以帮助我们了解研究领域的现状和发展&#xff0c;还可以为我们的论文提供理论支持和数据来源。然而&#xff0c;许多学者在查找文献时往往感到困惑和无所适从。本文将详细解释如何查找文献&#xff0…

柯桥专业会计培训|会计实操做账手工账电脑账出纳报税手把手教

开具纸质发票时&#xff0c;经常有小伙伴纠结发票开票人和复核人的问题。现在全国已施行数电票&#xff0c;这个问题还存在吗&#xff1f;一起来看看~ 暂未规定!! 开票人和复核人不应为同一人&#xff01; 目前&#xff0c;全国大部分城市已基本实现数电票的开票试点&#x…

Python学习:循环语句

Python循环语句 概念 循环语句是编程中常用的结构&#xff0c;用于多次执行相同或类似的代码块。Python中有两种主要的循环语句&#xff1a;for循环和while循环。 for循环&#xff1a; for循环用于遍历一个序列&#xff08;如列表、元组、字符串等&#xff09;中的元素&#x…

KIOXIA铠侠CM7系列E3.S双端口NVMe2.0 PCIe5.0 SSD KCM71RJE7T68

KIOXIA 铠侠推出的CM7-R E3.S企业级NVMe读密集型企业级固态硬盘&#xff0c;采用PCIe 5.0和NVMe 2.0技术&#xff0c;性能出色&#xff0c;最高可达2,700K IOPS&#xff08;随机读取&#xff09;和310K IOPS&#xff08;随机写入&#xff09;1 DWPD的耐用性和高达15.36 TB的存储…

教程4_轮廓特征(更多属性)

目标 在本章中&#xff0c;我们将学习 - 凸性缺陷以及如何找到它们 - 查找点到多边形的最短距离 - 匹配不同的形状 1. 凸性缺陷 我们看到了关于轮廓的第二章的凸包。从这个凸包上的任何偏差都可以被认为是凸性缺陷。 OpenCV有一个函数来找到这个 cv.convexityDefects()。一个…

剧变:人类社会与国家危机的转折点 - 三余书屋 3ysw.net

精读文稿 今天我们解读的这本书是《巨变》。副标题是人类社会与国家危机的转折点&#xff0c;这是一个充满风险和危机的时代。比如作为个人&#xff0c;我们可能会遭遇失业、离婚、亲朋好友的意外去世。作为国家&#xff0c;会遭遇经济危机、社会动荡甚至战争。整个世界也会陷入…

3.1. 状态空间方程

引言 状态空间方程是现代控制理论的基础&#xff0c;它以矩阵的形式表达系统的状态变量&#xff0c;输入及输出的关系。它可以描述和处理多输入多输出的系统。 目前流行的一些算法&#xff0c;比如&#xff1a;模型预测控制、卡尔曼滤波器及最优化控制都是在状态空间方程的表…

第二证券|固态电池概念拉升,丰山集团、丰元股份涨停,翔丰华等大涨

固态电池概念26日盘中强势拉升&#xff0c;截至发稿&#xff0c;丰山集团、丰元股份、科森科技等涨停&#xff0c;翔丰华涨超7%&#xff0c;瑞泰新材、鹏辉动力、天力锂能等涨超5%。 音讯面上&#xff0c;近来&#xff0c;智己联席CEO刘涛昨日发文称&#xff0c;智己L6将在准9…

【虚幻引擎】DTWebSocketServer 蓝图创建WebSocket服务器插件使用说明

本插件可以使用蓝图创建WebSocket服务器&#xff0c;并监听响应数据。 1. 节点说明 Create Web Socket Server – 创建WebSocket服务器对象并开启监听 创建一个WebSocket服务器对象&#xff0c;并监听相应端口&#xff0c;连接地址为 ws://IP:PORT, 比如ws://192.168.1.5:9001…

一本通差分约束入门题

最关键的就是找好所有的要满足的不等式条件&#xff0c;注意隐含的条件还有一点就是注意没有源点 建立源点 #2436. 「SCOI2011」糖果 #include<bits/stdc.h> using namespace std; using ll long long; using pii pair<int,int>; #define int long long const in…

视觉图像处理与FPGA实现第七次作业——生成512深度、8位宽度的双端口存储器IP,并分析IP包资料构成

一、生成IP 打开Vivado&#xff0c;点击IP Catalog&#xff0c;搜索memory&#xff0c;双击对应IP核 调整参数为——512深度、8位宽度&#xff0c;双端口&#xff0c;然后一直默认点击OK 二、分析IP构成 查看IP细节&#xff0c;查看设计资源和仿真资源 双击打开文件 设计文件…

【Java程序设计】【C00366】基于(JavaWeb)Springboot的纹理生产图片系统(有论文)

TOC 博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业六年&#xff0c;已经做了六年的毕业设计程序开发&#xff0c;开发过上千套毕业设计程序&#xff0c;博客中有上百套程序可供参考&#xff0c;欢迎共同交流学习。 项目简介 项目获取 &#x1f345;文末点击卡片…

20240325数据驱动的机器学习预测单层二维材料力学性能

本论文使用模型主要有Mo,W,S,Se原子组成的单层二维材料。大小为30nmx30nm&#xff0c;中间有切口&#xff0c;切口大小从无切口以1nm增长到5nm&#xff0c;加载方向垂直于切口方向&#xff0c;并且分锯齿型和扶手椅型方向。 使用MD对模型进行拉伸&#xff0c;一共288个模型。 …

【数据存储】TIDB和MySQL的区别

1.TIDB和MySQL对比 对比内容MySQLTiDB架构设计一个传统的单机数据库系统&#xff0c;采用主从复制和分区表等方式来实现水平扩展一个分布式的 NewSQL 数据库&#xff0c;采用分布式存储和分布式事务等技术&#xff0c;支持水平扩展和高可用性事务支持 InnoDB 存储引擎来支持事…

LeetCode3. 无重复字符的最长子串(Java)

给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长 子串 的长度。 示例 1: 输入: s "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc"&#xff0c;所以其长度为 3。示例 2: 输入: s "bbbbb" 输出: 1 解释: 因为…

【学习】软件测试中误区汇总分析

大家有没有想过这个问题&#xff1a;软件测试中有哪些误区呢&#xff1f;想起这个题目&#xff0c;是因为最近遇到好几次关于这方面的讨论。发觉即便做过几年测试的老员工也或多或少有些这方面的困惑。当然一家之言&#xff0c;仅作抛砖引玉之谈。 误区一&#xff1a;测试就是…

【Java程序设计】【C00364】基于Springboot的美发管理系统(有论文)

基于Springboot的美发管理系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 项目获取 &#x1f345;文末点击卡片获取源码&#x1f345; 开发环境 运行环境&#xff1a;推荐jdk1.8&#xff1b; 开发工具&#xff1a;eclipse以及idea&…

【双指针】Leetcode 202.快乐数

题目解析 Leetcode 202.快乐数 看完题目描述相信大家已经知晓题目的含义&#xff0c;我们通过一张图再剖析一下题目含义 快乐数或者非快乐数都是可以成环的&#xff0c;这个是数学上已经证明了的。所以这道题的最后含义就是分辨出环中全部是1或者全部没有1的 双指针 成环问…

服务器基础知识(物理服务器云服务器)

今天我们来介绍一下服务器的基础知识 一、服务器硬件基础知识 组件说明中央处理器&#xff08;CPU&#xff09;CPU是服务器的大脑&#xff0c;负责执行计算任务和指令。服务器通常配备多个CPU核心&#xff0c;以支持并行处理和提高性能。关键的CPU性能指标包括时钟频率、核心数…

大数据毕业设计Python+Spark知识图谱高考志愿推荐系统 高考数据分析 高考可视化 高考大数据 计算机毕业设计 机器学习 深度学习 人工智能 高考预测

意义 高考是中国的大学招生的学术资格考试&#xff0c;在目前看来&#xff0c;高考的考试类型有两种&#xff0c;一种是文理分科&#xff0c;另一种是新高考模式。传统的文理分科是将学生分成两个类型&#xff0c;一种是文科&#xff0c;除了语数外三门课以外需要学习政史地&am…