当前位置: 首页 > article >正文

【Linux网络编程】高效I/O--select/poll服务器

目录

多路转接之select

select服务器实现

获取连接

handlerEvent

select服务器代码链接 

select的优缺点 

多路转接之poll 

poll服务器实现(select服务器改写) 

poll的优缺点


多路转接之select

select的作用

I/O的本质 = 等 + 拷贝

多路转接就是通过同时等待多个文件描述符的方式实现效率的提升,这些在五种I/O模型中都详细说过!

select是实现多路复用I/O的一种方式

一个多路复用I/O可以分为两步:

  • 同时等待多个文件描述符
  • I/O条件就绪,直接进行拷贝

select完成的工作就是I/O等待这一步,即对多个文件描述符进行等待,若有一个或多个文件描述符读写条件就绪,select就会返回!

select返回后,即进行多路复用的第二步拷贝。拷贝是由read/write...这些拷贝函数实现的!


select调用

int select(int nfds, fd_set *readfds,fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
  • nfds:表示你需要监管的所有的文件描述符中,最大的文件描述符+1
  • readfds:指向fd_set的指针,包含需要监视的可读文件描述符
  • writefds:指向fd_set的指针,包含需要监视的可写文件描述符(可选)。
  • exceptfds:指向fd_set的指针,包含需要监视的异常文件描述符(可选)。
  • timeout:指定select进行等待时的等待规则
  • 返回值:若大于0,则表示实际I/O条件就绪的文件描述符的个数。若等于0,则表示超时。若小于0,则表示select发生错误,错误码被设置
  • 头文件:sys/select.h

以下是对select参数的详细介绍 


timeout参数 

 struct timeval类型的结构:

struct timeval {  long tv_sec;   // 秒数  long tv_usec;  // 微秒数  
};
  • 若tv_sec设置为0,且tv_usec设置为0,则表示的是select进行非阻塞等待。即便没有任何一个文件描述符就绪,select依旧会返回0
  • 若timeout参数设置为NULL,则表示select进行阻塞等待,在没有任何外部干扰(如信号中断)的情况下,若没有任何一个文件描述符就绪,则select永不返回,直到有一个或多个文件描述符就绪为止
  • 若timeout中的tv_sec或tv_usec设置为>0的数,此时的timeout是一个输入和输出型参数。例如timeout设置为5秒0微秒之后传入select,过了两秒以后有一个文件描述符就绪了,那么select返回,timeout被修改为3秒0微秒

fd_set类型 

读写条件就绪:

  • 若一个文件描述符可以进行读了,即该文件的内核接收缓冲区有数据了,我们称该文件描述符的读条件就绪
  • 若一个文件描述符可以进行写了,即该文件的内核发送缓冲区未满,我们称该文件描述符的写条件就绪

fd_set内部是一个对应文件描述符的位图结构

select参数中的fd_set类型参数含义:

  • readfds:该文件描述符集中比特位的值为1的文件描述符,select只关心该文件描述符的读条件是否就绪
  • writefds:该文件描述符集中比特位的值为1的文件描述符,select只关心该文件描述符的写条件是否就绪
  • exceptfds:该文件描述符集中比特位的值为1的文件描述符,select只关心该文件描述符的异常条件是否就绪
  • 若需要select同时关心一个文件描述符的读写条件,即把readfds和writefds对应位置的值同时设置为1
  • 若无需select关心异常时间,我们把exceptfds设置为空即可!

select参数中的三个文件描述符集都是即是输入型参数,又是输出型参数

  • 以readfds为例
  • 当readfds作为输入型参数的时候,表示的含义是:用户告诉内核需要关心readfds中所有的fd的读事件
  • 当readfds作为输出型参数的时候,表示的含义是:内核告诉用户需要关心的文件描述符中,有哪些已经就绪了

fd_set输入输出时位图的含义:

  • 当作为输入型参数的时候,比特位的位置表示的是第几号fd,比特位的值表示是否需要内核关心的文件描述符的xx事件。若比特位的值为0表示无需内核关心该文件描述符的xx事件,若比特位的值为1表示需要内核关心该文件描述符的xx事件
  • 当作为输出型参数的时候,比特位的位置表示的是第几号fd,比特位的值表示需要内核关心的文件描述符中,哪些已经就绪了。若比特位的值为0表示未关心或未就绪,若比特位的值为1表示已就绪

文件描述符集的操作

对fd_set的操作只允许使用系统调用,不允许自己去改,哪怕你已经知道了它是个位图

文件描述符集的头文件是:sys/select.h

清空(所有比特位清零)文件描述符集:FD_ZERO

void FD_ZERO(fd_set *set);
  • 功能:把set文件描述符集中的所有比特位清零 

清零文件描述符集中指定fd的值:FD_CLR

void FD_CLR(int fd, fd_set *set);
  • 功能:把set集中fd对应的比特位清零 

判断文件描述符集中指定fd的值:FD_ISSET

int  FD_ISSET(int fd, fd_set *set);
  • 功能:判断set集中fd对应的比特位是否为1
  • 返回值:就是set集中fd对应比特位的值。(若在即为1,若不在即为0)

新增(置为1)文件描述符集中指定fd:FD_SET

void FD_SET(int fd, fd_set *set);
  • 功能:把set集中fd对应的比特位置为1

select服务器实现

select服务器和一个简单的TCP服务器的区别主要体现在I/O上,所以我们基于我们之前写过的TCP服务器进行修改即可!TCP服务器

select服务器 vs 之前的TCP服务器

  • 相同点:都是要创建套接字并基于套接字进行通信,甚至构建套接字的过程都一摸一样
  • 不同点:select的I/O方案采用的是多路转接,而之前的TCP服务器是采用阻塞I/O的方式

基于上述原因,所以对于select服务器来说,只需要在TCP服务器的基础上,修改Loop函数即可


获取连接

accept的本质其实也是I/O,I/O = 等 + 拷贝,accept也是等+拷贝。

所以新连接到来时就等价于有了读事件。

读事件可以由select进行监管,即可以把listen套接字添加到readfds中

把listen套接字交由select进行监管要完成的3个步骤:

  • 定义fd_set
  • 填充fd_set
  • 系统调用select 

 select获取到哪些fd条件就绪,进行返回时,我们要根据select的返回值来分情况处理

  • 若select的返回值大于0,表示已经有多少个文件描述符的条件就绪。上层已经可以根据readfds进行处理了
  • 若select的返回值等于0,则表示超时。若select是阻塞监管,那么select不会返回0。
  • 若select的返回值小于0,则表示select发生错误。
    void Loop() // 修改I/O为select{while(true)//需要不断获取连接,打上死循环即可{//定义fd_setfd_set rfds;//填充fd_setFD_ZERO(&rfds);FD_SET(_listensock,&rfds);//调用selectint n = select(_listensock + 1 , &rfds,nullptr,nullptr,nullptr);//select只关心读事件,并且阻塞等待if(n > 0){//表示已经有文件描述符条件就绪了,此时rfds中比特位为1的位置就是已经就绪的文件描述符handlerEvent(rfds);}else if(n == 0){//阻塞等待不会走到这std::cout << "timeout..." << std::endl;}else {std::cerr << "Select Error!" << std::endl;exit(2);}}

handlerEvent

上述,我们已经将listen套接字交给select进行监管了。那么若listen套接字读条件就绪,即有客户端向发送连接时,如何处理呢?

这就由handlerEvent进行处理

由于select监管的文件描述符可能是listen套接字,也可能是普通套接字,所以我们需要对这两种套接字进行分类讨论

对于listen套接字来说:

  • listen套接字的读事件就绪,也就意味着有新的客户端连接到来,我们首先要accept新连接
  • accept过后会获取一个新的普通套接字,我们需要把普通套接字交给select进行监管

对于普通套接字来说:

  • 普通套接字的读事件就绪,也就意味着客户端发来了一条新的I/O数据
  • 此时服务器提供服务即可! 

细节问题:辅助数组

当用户调用select传入rfds时,此时的rfds是输入型参数

当select返回时,此时的rfds是输出型参数

rfds作为输入型参数和输出型参数时,含义是完全不同的!

举个例子:若我们调用select时设置了1号3号5号文件描述符的读事件。假设select在监管时只有3号文件描述符就绪了,那么select会直接修改rfds,此时没有就绪的文件描述符就被修改了

 

  • rfds被select修改了,但我们之后还需要关心1号和5号文件描述符的读事件! 

为了解决这个问题,所以调用select时一般会搭配上一个辅助数据结构来实现!(以数组为例)

辅助数组中一般会存储调用select之前的rfds,方便内核修改了rfds后,用户进行重新设置

在服务器构造的时候,我们可以直接构造好辅助数组,此外,辅助数组我们可以直接设置为成员变量

class TCPServer
{
public:const static int N = sizeof(fd_set) * 8; //辅助数组的大小const static int defaultfd = -1; //辅助数组元素的初始值TCPServer(uint16_t port): _port(port), _isrunning(false){//初始化辅助数组for(int i = 0 ; i < N ; ++i){fd_array[i] = defaultfd;}//listen套接字是必须要的,直接添加进辅助数组}
protected:uint16_t _port;int _listensock;bool _isrunning;int fd_array[N]; //辅助数组,元素的含义是需要内核关心的套接字编号
};

注意:该服务器的listensock是在初始化套接字时创建的,在socket创建listensock的后面再把listen套接字传入到辅助数组中  


handlerEvent的实现 

通过之前介绍select调用,我们会发现若我们不通知内核需要关心某个fd,那么select返回时这个fd一定不会在rfds中。

  • 若我们告诉内核需要关心第n号文件描述符,那么select返回时该文件描述符不一定会就绪
  • 若我们不告诉内核需要关心第n号文件描述符,那么select返回时该文件描述符一定不会就绪

除此之外,select返回时,可能不止一个文件描述符就绪了

所以第一步我们需要遍历整个辅助数组

  • 若遍历过程中,fd_array[i]的值是默认值,说明该位置还没被使用,直接跳过即可
  • 若遍历过程中,fd_array[i]的值不是默认值,意味着该位置存储的一定是需要内核关心的文件描述符的编号,此时需要看这个文件描述符是否在输出型参数rfds中,若在,则该文件描述符就绪。否则,该文件描述符没就绪
  • 判断一个文件描述符是否在fd_set中,我们使用的调用是FD_SET 

第二步就是分类讨论,区分该套接字是listen套接字还是普通套接字

    void handlerEvent(fd_set &rfds){for(int i = 0 ; i < N ; ++i){//若该fd不在辅助数组中,说明该文件描述符一定不会就绪if(fd_array[i] == defaultfd) continue;//走到这,说明该文件描述符被关心,经过rfds判断是否就绪if(!FD_ISSET(fd_array[i],&rfds)) continue; //区分处理if(fd_array[i] == _listensock){//该套接字是listen套接字,完成的工作是处理连接AcceptClient();}else {//该套接字是普通套接字,完成的工作是提供I/O服务Service(fd_array[i]);}}}

处理连接:AcceptClient 

 到这一步,说明listen套接字的读事件已经就绪

需要进行两步操作:

  • 获取新连接,并获取新的套接字
  • 把套接字交给select进行监管

如何交给select进行监管?把这个新的套接字设置进辅助数组即可

    void AcceptClient(){//1.获取新连接,获取新的套接字int sockfd;Accept(sockfd);//2.把新连接设置进辅助数组int pos = 1;for(; pos < N ; ++pos){//2.1选择一个没被用过的位置 if(fd_array[pos] == defaultfd) break;}if(pos < N){//2.2找到了一个没有被用的空位置fd_array[pos] = sockfd;}else{//pos == N//2.3说明fd_array已经被使用满了close(sockfd);std::cerr << "Server is full!" << std::endl;}}

 提供服务:Service

Service注意不要死循环即可! 

    void Service(int sockfd){//获取客户端的输入char buffer[1024];int n = recv(sockfd, buffer, sizeof(buffer), MSG_WAITALL);if (n > 0){// 接收成功std::cout << "Client say# " << buffer << std::endl;// 服务器把buffer中的数据重新发送给客户端,完成服务//发送客户端的输入send(sockfd, buffer, sizeof(buffer), 0);}else if (n == 0){// 客户端套接字关闭std::cout << "client socket close!" << std::endl;close(sockfd);}else{// recv errorstd::cerr << "recv error!" << std::endl;close(sockfd);exit(5);}}

修改Loop函数

Loop函数的修改主要有几点 

  • 先把listen套接字放入辅助数组
  • 每一次循环都得遍历一遍辅助数组,构建fd_set输入型参数,用于传递select参数
  • 遍历过程中找出最大的文件描述符,用于传递select参数
    void Loop() // 修改I/O为select{fd_array[0] = _listensock;while(true)//需要不断获取连接,打上死循环即可{//定义fd_setfd_set rfds;//填充fd_setFD_ZERO(&rfds);//max_fd主要用于select参数填写int max_fd = defaultfd;for(size_t i = 0 ; i < N ; ++i){if(fd_array[i] == defaultfd) continue;FD_SET(fd_array[i],&rfds);if(fd_array[i] > max_fd) max_fd = fd_array[i]; }//调用selectint n = select(max_fd + 1 , &rfds,nullptr,nullptr,nullptr);//select只关心读事件,并且阻塞等待if(n > 0){//表示已经有文件描述符条件就绪了,此时rfds中比特位为1的位置就是已经就绪的文件描述符handlerEvent(rfds);}else if(n == 0){//阻塞等待不会走到这std::cout << "timeout..." << std::endl;continue;}else {std::cerr << "Select Error!" << std::endl;continue;}}}

select服务器代码链接 

select服务器实现


select的优缺点 

优点:

  • 与其他I/O模型相比,select可以同时等待多个fd。对I/O性能有着显著提升
  • select是最早出现的多路转接的方案,在很多较旧的服务器或系统上,select仍然会被使用 

缺点:

  • 同时等待的fd的个数,有上限。这一缺点是由于fd_set类型被设置为固定大小的位图。通常为1024个比特位
  • select输入输出参数混合。每次都要进行重新设定。通过服务器的编写我们会发现,使用select往往会造成大范围的遍历,而遍历对性能的损耗其实也是蛮大的
  • 内核和用户之间的数据拷贝,这个缺点所有的多路转接方案都会存在
  • select底层监视多个fd的时候,OS会在内部进行遍历检测所有的fd,至少有一个就绪就返回。如果没有,就按照策略!

由于select的缺点比较多,所有后来提出的多路转接方案都是基于这些缺点进行的改良。

其中,我们接下来介绍的poll就对select的某些缺点进行了改良 


多路转接之poll 

poll对select进行一定程度的改良

  • poll解决了select同时等待fd有上限的问题
  • poll解决了select输入输出混合,导致代码中出现多次遍历的问题

poll接口 

       #include <poll.h>int poll(struct pollfd *fds, nfds_t nfds, int timeout);
  • timeout:poll的timeout是输入型参数,poll等待时按照timeout的策略进行等待,可以类比select的timeout参数,poll的timeout的单位是ms(毫秒),若poll在等待了timeout毫秒后还没有任何fd就绪,那么poll会超时返回。特殊的:若timeout被设置为0则表示非阻塞等待。若timeout被设置为-1则表示阻塞等待
  • fds和nfds:这两个合起来我们可以看成是一个数组,其中nfds表示的是数组的元素个数,而fds表示数组的首元素地址。数组的元素类型是struct pollfd。

poll如何解决select输入输出参数混合的问题的? 

 poll的fds实际上也是一个输入且输出型参数!

struct pollfd结构:

           struct pollfd {int   fd;         /* file descriptor */short events;     /* requested events */short revents;    /* returned events */};
  • fd:表示需要关心的文件描述符编号
  • events:请求事件,这是用于用户告诉内核需要关心fd的哪些事件,若这个参数用户设置为POLLIN,则表示需要关心fd的读事件。若这个参数用户设置为POLLOUT,则表示需要关心fd的写事件。若用户既想关心读,又想关心写,则 POLLOUT | POLLIN即可,也就是说参数可以进行组合
  • revents:返回事件,这是内核告诉用户,指定fd的哪些事件好了!若用户想看看该fd的读事件是否就绪,则revents & POLLIN即可!

poll的事件除了读写以外还有哪些:(man手册有详细介绍) 

我们可以看出,poll的fds参数虽然还是输入输出型的参数,但用户通知内核和内核通知用户所用的变量不再是同一个,这就是poll解决输入输出混合问题的方案 


poll如何解决select同时等待的fd有上限的问题? 

从参数上,我们已经可以猜到它的解决方案了

poll的fds参数和nfds参数是配合使用的,fds相当于数据首元素地址,nfds是由用户确定的,换句话来说,只要用户想且内存允许,你的fd想要多少就有多少!不会受到poll接口的影响


poll服务器实现(select服务器改写) 

经过select服务器的铺垫,poll服务器改写起来是相对容易的:poll服务器的改写代码


poll的优缺点

优点:

  • poll在select的基础上,弥补了select的一些缺点。并且poll也是多路转接方案的一种,与其他四种I/O模型相比,poll的优点是它可以同时接收多个文件描述符
  • poll在select的基础上,弥补了select同时等待的fd有上限的问题,poll则是完全由用户自主决定fd的大小。
  • poll在select的基础上,弥补了select输入输出参数混合的问题,每次调用poll时,都不再需要重新遍历设定参数!

缺点:

  • poll与我们后续所学习的epoll相比,它的缺点是底层poll在检查fd是否就绪时,仍然采用的是遍历整个fd数组的方式,效率较低
  • poll虽然比起select来说较优,但由于其出现的时间点和技术发展的趋势,大多数旧的设备/服务器当中,都已经采用了select。而对于新的设备/服务器来说,poll被epoll所替代。所以poll所处的地位较为尴尬
  • 内核和用户之间的数据拷贝,这个缺点所有的多路转接方案都会存在

相关文章:

【Linux网络编程】高效I/O--select/poll服务器

目录 多路转接之select select服务器实现 获取连接 handlerEvent select服务器代码链接 select的优缺点 多路转接之poll poll服务器实现(select服务器改写) poll的优缺点 多路转接之select select的作用 I/O的本质 等 拷贝 多路转接就是通过同时等待多个文件描述…...

2024年第十五届蓝桥杯大赛软件赛省赛Python大学A组真题解析

文章目录 试题A: 拼正方形(本题总分:5 分)解析答案试题B: 召唤数学精灵(本题总分:5 分)解析答案试题C: 数字诗意解析答案试题A: 拼正方形(本题总分:5 分) 【问题描述】 小蓝正在玩拼图游戏,他有7385137888721 个2 2 的方块和10470245 个1 1 的方块,他需要从中挑出一些…...

C语言实战项目(1)---------->猜数字游戏

在学习完循环和选择结构之后&#xff0c;我们可以做一个猜数字游戏。在此项目之前&#xff0c;如果还不会C语言的if语句、switch语句等组成选择结构的语句&#xff0c;while循环、for循环、do-while循环等组成循环结构的语句。可以参考我之前的博客&#xff1a; C语言&#xf…...

web理论总结

1.网页&#xff1b;可以承载各种网址应用和信息的容器&#xff0c;所有可视化的内容都会通过网页展示给用户。 2.网页主要由文字&#xff0c;图像和超链接等元素构成。还可以包含音频&#xff0c;视频以及动画等。 网页分为静态网页&#xff0c;动态网页大部分网页静动结合。…...

Failed to start The PHP FastCGI Process Manager.

报错如下&#xff1a; Job for php-fpm.service failed because the control process exited with error code. See "systemctl status php-fpm.service" and "journalctl -xe" for details. 2月 25 21:49:00 nginx systemd[1]: Starting The PHP FastC…...

001 Kafka入门及安装

Kafka入门及安装 文章目录 Kafka入门及安装1.介绍Kafka的基本概念和核心组件 2.安装1.docker快速安装zookeeper安装kafka安装 添加topic删除topickafka-ui安装 来源参考的deepseek&#xff0c;如有侵权联系立删 1.介绍 Kafka的基本概念和核心组件 Kafka是分布式流处理平台&a…...

【paddle】详解 padde.autograd.backward

目录 backward二次函数案例paddle 代码pytorch 代码 backward paddle.autograd.backward(tensors, grad_tensorsNone, retain_graphFalse)[源代码] 参数 tensors (list[Tensor]) – 将要计算梯度的 Tensors 列表。Tensors 中不能包含有相同的 Tensor。grad_tensors (None|list…...

飞腾腾锐D2000 + OpenHarmony 4.1release部署deepseek大模型

简介 1.1 飞腾腾锐D2000 飞腾腾锐D2000是一款面向桌面应用的高性能通用处理&#xff0c;集成8个飞腾自主研发的高能效处理器核FTC663&#xff0c;兼 容64位ARMv8指令集并支持ARM64和ARM32两种执行模式&#xff0c;支持单精度、双精度浮点运算指令和ASIMD处理 指令&#xff0c;主…...

【REST2SQL】15银河麒麟系统下达梦数据库部署REST2SQL

【REST2SQL】01RDB关系型数据库REST初设计 【REST2SQL】02 GO连接Oracle数据库 【REST2SQL】03 GO读取JSON文件 【REST2SQL】04 REST2SQL第一版Oracle版实现 【REST2SQL】05 GO 操作 达梦 数据库 【REST2SQL】06 GO 跨包接口重构代码 【REST2SQL】07 GO 操作 Mysql 数据库 【RE…...

晶体管输出光耦和逻辑输出光耦

晶体管输出光耦&#xff08;非线性&#xff09;和逻辑输出光耦&#xff08;线性&#xff09;的区别&#xff1a; 逻辑输出光耦的电流传输特性曲线是非线性的&#xff0c;适合于开关信号的传输&#xff0c;不适合于传输模拟量&#xff1b; 光电晶体管输出光耦的电流传输特性是线…...

智能生活综合平台需求规格说明书

一、引言 1.1 编写目的 本需求规格说明书旨在明确智能生活综合平台的功能、性能、用户界面等方面的需求&#xff0c;为平台的开发、测试和部署提供详细的指导&#xff0c;确保平台能够满足用户在社交、购物、教育、医疗、政务等多个领域的智能生活需求&#xff0c;提升用户的…...

绕过过滤order by

一、常见绕过技术 1、注释符截断 利用注释符&#xff08;如 --、#&#xff09;截断后续查询&#xff0c;消除过滤逻辑的影响。 ORDER BY 1-- 若原查询为 SELECT * FROM table ORDER BY 用户输入&#xff0c;注入后可能忽略后续过滤逻辑。 2、大小写混淆/编码绕过 若过滤是大…...

计算机网络之传输层(传输层的功能)

一、数据分段与重组 传输层从会话层接收数据&#xff0c;并将其分割成较小的数据段&#xff0c;以适应网络层的最大传输单元&#xff08;MTU&#xff09;限制。在目的端&#xff0c;传输层负责将这些数据段重新组合成原始数据&#xff0c;确保数据的完整性和正确性。 二、端口…...

面试八股文--数据库基础知识总结(1)

1、数据库的定义 数据库&#xff08;DataBase&#xff0c;DB&#xff09;简单来说就是数据的集合数据库管理系统&#xff08;Database Management System&#xff0c;DBMS&#xff09;是一种操纵和管理数据库的大型软件&#xff0c;通常用于建立、使用和维护数据库。数据库系统…...

优化 Flink 消费 Kafka 数据的速度:实战指南

在使用 Flink 消费 Kafka 数据时&#xff0c;你可能会遇到 消费速率较慢 的问题。本文将从 Kafka 并行消费、批量拉取、Checkpoint 频率、Consumer Poll 速率 以及 Flink 任务 Slot 资源 等多个方面&#xff0c;详细解析如何优化 Flink 消费 Kafka 的速度。 &#x1f525; 1. 增…...

轮式机器人在复杂地形中如何选择合适的全局路径规划算法?

已思考完成 收起 嗯&#xff0c;用户问的是轮式机器人在复杂地形中如何选择合适的全局路径规划算法。首先&#xff0c;我需要理解复杂地形可能带来的挑战&#xff0c;比如崎岖的路面、动态障碍物、非结构化环境等等。轮式机器人在这里的运动控制需要考虑地形通过性、稳定性&…...

数据结构与算法:动态规划dp:买卖股票相关力扣题(下):309. 买卖股票的最佳时机含冷冻期、714. 买卖股票的最佳时机含手续费

309. 买卖股票的最佳时机含冷冻期 首先我们要明确&#xff0c;如果全程只能买卖一次或者允许买卖多次&#xff0c;那么我们就没必要记录无操作这个状态。 如果买卖的次数为k&#xff08;k≥2&#xff09;&#xff0c;那么我们才要记录无操作这个状态&#xff0c;以此来区分具体…...

[uboot][stm32]配置LTDC屏幕

文章目录 前提dts设备树修改Kconfig日志打印后记 https://github.com/wdfk-prog/u-boot 前提 手上刚好有块屏幕,尝试在uboot中点亮一下使用前请使用其他手段点亮该屏幕确保屏幕的完好再进行操作.确保配置的参数及引脚是可用的. dts设备树修改 ltdc状态修改为重定向前绑定,另…...

机试刷题_1614. 括号的最大嵌套深度【python】

1614. 括号的最大嵌套深度 class Solution:def maxDepth(self, s: str) -> int:maxD 0if not s:return maxDstack []for char in s:if char(:stack.append(char)maxD max(maxD,len(stack))elif char) :stack.pop()return maxD...

VM虚拟机安装与配置Ubuntu Linux操作系统详细教程~

一、下载VM虚拟机 VMware16.0.zip百度网盘下载链接:https://pan.baidu.com/s/1-l-CcAVNINqhRLSiQ26R7w?pwd=tznn 提取码: tznn 二、软件介绍 VMware(虚拟机)是指通过软件模拟的具有完整硬件系统功能的、运行在一个完全隔离环境中的完整计算机系统,通过它可在一台电脑上同…...

2025年2月科技热点深度解析:AI竞赛、量子突破与开源革命

引言 2025年的科技领域持续呈现爆发式增长&#xff0c;AI大模型竞争白热化、量子计算商业化加速、开源工具生态繁荣成为本月最受关注的议题。本文结合最新行业动态&#xff0c;从技术突破、商业布局到开发者生态&#xff0c;全面解析当前科技热点&#xff0c;为读者提供深度洞…...

免费PDF工具

Smallpdf.com - A Free Solution to all your PDF Problems Smallpdf - the platform that makes it super easy to convert and edit all your PDF files. Solving all your PDF problems in one place - and yes, free. https://smallpdf.com/#rappSmallpdf.com-解决您所有PD…...

组件注册方式、传递数据

组件注册 一个vue组件要先被注册&#xff0c;这样vue才能在渲染模版时找到其对应的实现。有两种注册方式&#xff1a;全局注册和局部注册。&#xff08;组件的引入方式&#xff09; 以下这种属于局部引用。 组件传递数据 注意&#xff1a;props传递数据&#xff0c;只能从父…...

IPD流程适合创业团队吗?

目录 简介 创业团队 作者简介 简介 回答这个问题&#xff0c;就不能只局限于 IPD 流程本身。 而是要先回答为什么需要 IPD 流程&#xff1f; 在 IPD 思维这篇文章&#xff0c;我也强调过这个观点&#xff1a; IPD 本身是为过剩经济量身定做的一种模式、一种思维。 包括…...

异步fifo学习

FIFO 本质是由 RAM 加上读写逻辑构成的先入先出的数据缓冲器。与 RAM 的区别是 FIFO 没有外部读写地址线&#xff0c;顺序写入顺序读出数据&#xff0c;其数据地址是由内部读写指针自增完成&#xff0c;因此 FIFO 在读写时不需要考虑读写冲突的问题。 根据 FIFO 工作的时钟域&a…...

【有啥问啥】All-to-All 通信:原理、实现与应用

All-to-All 通信&#xff1a;原理、实现与应用 一、引言 在分布式计算和并行处理领域&#xff0c;进程之间的通信是至关重要的。All-to-All 通信作为一种高效的通信模式&#xff0c;广泛应用于各种高性能计算和分布式系统中。本文将详细介绍 All-to-All 通信的定义、工作原理…...

深度学习(3)-TensorFlow入门(常数张量和变量)

低阶张量操作是所有现代机器学习的底层架构&#xff0c;可以转化为TensorFlow API。 张量&#xff0c;包括存储神经网络状态的特殊张量&#xff08;变量&#xff09;​。 张量运算&#xff0c;比如加法、relu、matmul。 反向传播&#xff0c;一种计算数学表达式梯度的方法&…...

Python学习第十七天之PyTorch保姆级安装

PyTorch安装与部署 一、准备工作二、pytorch介绍三、CPU版本pytorch安装1. 创建虚拟环境2. 删除虚拟环境1. 通过环境名称删除2. 通过环境路径删除 3. 配置镜像源4. 安装pytorch1. 首先激活环境变量2. 进入pytorch官网&#xff0c;找到安装指令 5. 验证pytorch是否安装成功 四、…...

HTML邮件的制作以及遇到的问题

以下是关于HTML邮件制作的详细步骤以及可能遇到的问题和解决办法&#xff1a; 一、HTML邮件制作步骤 规划邮件结构&#xff1a;确定邮件的主题、主要内容、目标受众等。比如是营销推广邮件、新闻通讯邮件还是通知邮件等。例如&#xff0c;营销推广邮件可能需要突出产品特点和…...

GPT-5倒计时:2025年AI海啸来袭,机器与人类对话临近

大家好&#xff0c;我是Shelly&#xff0c;一个专注于输出AI工具和科技前沿内容的AI应用教练&#xff0c;体验过300款以上的AI应用工具。关注科技及大模型领域对社会的影响10年。关注我一起驾驭AI工具&#xff0c;拥抱AI时代的到来。 人工智能&AIGC术语100条 Shelly聊AI-重…...