【计算机网络】多路复用的三种方案
文章目录
- 1. select
- select函数
- select的工作特性
- select的缺点
- 2. poll
- poll函数
- poll与select的对比
- 3. epoll
- epoll的三个接口
- epoll的工作原理
- epoll的优点
- LT和ET模式
- epoll的应用场景
🔎Linux提供三种不同的多路转接(又称多路复用)的方案,分别是:select,poll和epoll。它们表现为不同的系统调用接口。
前置知识:“IO事件就绪”
即读事件就绪或写事件就绪
- 读事件就绪,指接收缓冲区中有数据可以读取
- 写事件就绪,指发送缓冲区中有空间可以写入
1. select
select是Linux中用于同时监视多个文件描述符是否就绪的系统调用接口,当程序运行到select调用处,默认会阻塞等待(也可以设为非阻塞)监视的文件描述符至少有一个IO事件就绪为止。
select函数
#include <sys/select.h>int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
参数介绍:
- nfds:需要监视的文件描述符最大值+1;
- readfds/writefds/exceptfds:分别是监视的读文件描述符集合,写文件描述符集合,异常文件描述符集合。这三个fd_set*类型的参数是输入输出型函数,如:你需要关心某个fd的读事件,就将其设置到
readfds中并调用select,select返回时,若该fd的读事件就绪,则readfds存在该fds,否则不存在。writefds和exceptfds同理。总而言之,这三个参数既让用户告知内核"我"要关心哪个文件fd,又让内核向用户通知哪些文件fd的哪些事件已就绪。 - timeout:select等待超时时间,设为nullptr则为阻塞等待。
返回值:
-
成功,则返回三个fd_set中事件就绪的fd的个数,若为0,表示超时timeout了也没有fd的事件就绪
-
失败,返回-1,错误码被设置,此时参数readfds, writefds,exceptfds和timeout的值失效
fd_set结构:
fd_set底层是一个long int的数组,上层视作一个位图结构,每个比特位,下标代表文件fd,内容表示fd是否有效。若调用select时,参数readfds的位图结构为
...00001000(前面全0省略),则表示用户需要监视3号文件描述符的读事件,select返回时,若readfds依然为...00001000,表示3号文件描述符读事件就绪,否则未就绪。

提供了一组操作fd_set的接口,来比较方便的操作位图
void FD_CLR(int fd, fd_set *set); // 将fd从set中去除
int FD_ISSET(int fd, fd_set *set);// 判断fd是否存在于set中
void FD_SET(int fd, fd_set *set); // 将fd设置入set中
void FD_ZERO(fd_set *set); // 清空set
select的工作特性
-
select在内核中会去遍历三个fd_set,对于每个fd,若用户关心,则检测该fd的对应事件是否就绪,就绪则比特位置1,反之置0,若用户不关心,则跳过。参数
nfds是底层遍历的终点。这种遍历在阻塞情况下会持续进行,直到检测到有一个或多个fd的IO事件就绪为止。 -
select能够监视的文件fd是有限的,这受限于fd_set的大小,
fd个数 = sizeof(fd_set) * 8。不同环境下的fd_set大小不同,在我的本地测试sizeof(fd_set) = 128,那么能够监视的fd个数即为1024。 -
将关心的fd加入select的监控集合后,还需要在上层维护一个数组array来保存这些关心的fd。原因如下:
-
一,select的三个fd_set都是输入输出型参数,那么select前设置的fd,在select后可能就不存在了(因为该fd的事件未就绪),因此每次select之前都需要重置fd_set,重置就需要有一个数组array始终保存着用户关心的fd。
-
二,select返回后,用户需要手动遍历fd_set,判断哪些fd已就绪(FD_ISSET),而上层保存fd的数组array就是判断的根据。
-
select的缺点
- 每次select之前都要手动重置fd_set,太麻烦了
- 每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大
- 每次调用select,都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大
- select支持的文件描述符数量太小
2. poll
poll的作用和工作特性与select基本相同,但使用方法不同。
poll函数
#include <poll.h>int poll(struct pollfd *fds, nfds_t nfds, int timeout);
poll以结构体struct pollfd的形式规定了监视的fd,其中包含更多信息。

fd:监视的fd
events:这是用户设置的,用于用户告知内核本fd要监视什么事件,是输入型参数
revents:这是poll函数返回的,用于内核通知用户本fd的哪些事件已就绪,是输出型参数
events/revents的事件类型:
POLLIN:读事件
POLLOUT:写事件
POLLERR:错误异常
POLLHUP:挂起异常,可能是对端关闭了连接
以上事件类型都是<poll.h>中定义的宏,events/revents可以同时承载多个事件,只需多个事件类型进行与操作即可。
poll的参数介绍
- fds:
struct pollfd类型的指针,指向一段连续存放多个pollfd的空间。fds由用户自己维护。 - nfds:fds指向空间的大小
- timeout:超时时间,单位是毫秒ms
💭一些小细节:
- 在pollfd中,若fd为负数,则events无效,调用poll后,revents被设为0
- 在pollfd中,若events为0,表示不关心该fd上的任何时间,那么调用poll后,revents也将被设为0。
- poll只会监视fd用户关心的事件,并通过revents返回
poll的返回值:
- 成功,返回有事件就绪的fd的个数,即revents不为0的pollfd的个数。若为0,表示超时timeout了也没有fd的事件就绪。
- 失败,返回-1,错误码被设置。
poll与select的对比
- poll相比于select的优势有两点:
- 输入与输出分离,不用在每次调用poll前手动设置关心的fd
- 能够关心的fd个数不受限制,fds指向的空间用户可以扩容,参数nfds也可以修改
- 与select一样存在频繁遍历的劣势。监视的fd一多,每次调用poll,要将大量的pollfd结构从用户态拷贝到内核中,内核要遍历传递进来的所有pollfd结构,检查有哪些事件就绪。每次poll返回,都需要遍历上层维护的pollfd结构,根据revents判断哪些fd的什么事件就绪了。
- 同时连接的大量客户端在一时刻可能只有很少的处于就绪状态,因此随着监视的描述符数量的增长,遍历速度降低,其效率也会线性下降。
3. epoll
epoll是目前公认的效率最高,性能最佳的多路复用组件。
epoll的三个接口
-
epoll_create
功能:创建一个epoll模型的句柄,返回该句柄的文件描述符
函数原型:
#include <sys/epoll.h>int epoll_create(int size);注意事项:
- 自从linux2.6.8之后,size参数是被忽略的,随便给一个就行
- 使用结束,必须调用close()关闭epoll句柄
-
epoll_ctl
功能:对epoll模型进行增、删、改的操作(本质是对红黑树的操作)
函数原型:
#include <sys/epoll.h>int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);参数:
epfd:epoll句柄的文件描述符,由
epoll_create获得;fd:目标文件描述符;
op:操作类型,有如下三种:
- EPOLL_CTL_ADD:将新的fd注册到epoll模型中,表示关心fd的事件发生
- EPOLL_CTL_MOD:修改fd的关心事件
- EPOLL_CTL_DEL:将fd从epoll模型中移除,表示不再关心fd的事件发生
event:struct epoll_event结构体类型如下
typedef union epoll_data {void *ptr;int fd;uint32_t u32;uint64_t u64;} epoll_data_t;struct epoll_event {uint32_t events; /* Epoll events */epoll_data_t data; /* User data variable */};events:表示fd关心的事件。events可以是以下几个宏的集合:
宏名称 意义 用户设置 内核返回 EPOLLIN 表示对应的文件描述符可以读 (包括对端SOCKET正常关闭) ✅ ✅ EPOLLOUT 表示对应的文件描述符可以写 ✅ ✅ EPOLLERR 表示对应的文件描述符发生错误 ❎ ✅ EPOLLHUP 表示对应的文件描述符被挂断 ❎ ✅ EPOLLET 将EPOLL设为边缘触发(Edge Triggered)模式 ✅ ❎ data:epoll_data类型的联合体,包含文件描述符的信息,可选择四种不同类型表示,一般选用
int fd返回值:成功返回0,错误返回-1,错误码被设置。
-
epoll_wait
功能:等待epoll模型上的就绪事件
函数原型:
#include <sys/epoll.h>int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);参数:
epfd:epoll句柄的文件描述符,由
epoll_create获得;events:指向一组连续存放的epoll_event结构体,epoll_wait会从内核拷贝已就绪的事件到events指向的空间中;
maxevents:events最多存epoll_event数量,maxevents的值不能大于创建epoll_create()时的size;
timeout:超时时间,单位是毫秒ms。-1表示阻塞等待。
epol_wait的返回值:
- 成功,返回有事件就绪的fd的个数,即events的单元个数。若为0,表示超时timeout了也没有fd的事件就绪。
- 失败,返回-1,错误码被设置。
epoll的工作原理
epoll的内核实现,采用所谓的"epoll模型",是由一个红黑树(rbtree)和一个就绪队列(rdlist)组成,用于高效的监控文件描述符的状态变化。在内核中搭建epoll模型(创建rbtree和rdlist),并创建一个eventpoll句柄,用户持有eventpoll句柄的文件描述符,eventpoll句柄存有rbtree的根节点指针和rdlist的头结点指针,能找到内核中的epoll模型。eventpoll句柄成为用户与内核epoll沟通的桥梁。

🔎epoll的工作机制,由以下三部分构成:
-
红黑树rbtree
根据先描述再组织的管理思想,epoll对于每一个关心的文件描述符,先将其描述为epitem结构体,再挂载到红黑树rbtree当中,并在rbtree中完成各种操作。如:epoll_ctl的EPOLL_CTL_ADD操作,就是先将新的文件描述符描述为一个epitem结构体,再插入到内核epoll的红黑树中。同理,EPOLL_CTL_MOD和EPOLL_CTL_DEL就是对红黑树的改和删的工作。
struct epitem{struct rb_node rbn; //红黑树节点struct list_head rdllink; //双向链表节点struct epoll_filefd ffd; //文件描述符的句柄信息struct eventpoll *ep; //指向其所属的eventpoll对象struct epoll_event event; //期待发生的事件类型 }struct epoll_event是epitem的key值,也是用户告知内核关心事件,内核通知用户就绪事件的结构体。
-
就绪队列rdlist
rdlist就绪队列,其实是一个双向链表结构,用于存放rbtree中已就绪的事件节点。epoll会将rbtree中事件就绪的epitem节点,推送到rdlist中,用户调用epoll_wait实际上就是将rdlist中的就绪事件拷贝到参数events中,时间复杂度为O(1)。值得注意的是,rdlist中的节点并不是rbtree中的副本,“节点从rbtree推送到rdlist”这个动作实际上只是修改节点的连接关系(epitem中的
struct list_head rdllink),而不是拷贝一份到rdlist中。
关于rdlist的增与删
rdlist的增由回调机制决定,当某个fd的IO事件就绪,执行回调函数将fd对应的epitem节点连接到rdlist中。对于LT模式,只要fd的IO事件依然就绪,就继续保留fd对应的epitem节点在rdlist中;对于ET模式,epoll_wait读取一次,就将节点从rdlist中移除。
-
回调机制ep_poll_callback
“节点从rbtree推送到rdlist”是怎么做到的?首先,在调用epoll_ctl注册新的文件描述符时,会为这个文件描述符对应的epitem在底层的注册一个回调函数,这个回调的功能是将节点连接到rdlist中(回调函数注册到fd的文件句柄中)。此后,当底层IO事件就绪(协议栈决定), 检测到对应文件句柄的回调函数存在,就会调用这个回调函数,将epitem节点连接到rdlist中。
epoll的优点
- 内核采用红黑树结构管理关心的文件描述符,上层不需要再像select/poll那样自行维护关心的文件描述符,也不需要再手动设置每次要关心的文件描述符。
- 红黑树结构的增删查改效率很高(时间复杂度是
O(lgN)),不会因为关心fd的增多,导致新文件描述符的添加、关心事件的修改、文件描述符的移除等操作的效率降低。 - 不需要再像select/poll那样轮询检测哪些fd的事件就绪,而是采用回调机制将活跃节点连接到rdlist中,用户仅需通过就绪队列rdlist获取就绪事件,这样一来避免了频繁的遍历,即使文件描述符很多,也没有影响。
总而言之,epoll只关注活跃的fd,不会像select/poll一样总是全局扫描所有的fd,这大大提高了它的效率。
LT和ET模式
epoll有两种工作模式,水平触发(LT, Level Triggered)和边缘触发(ET, Edge Triggered)
-
LT模式:只要fd的IO事件一直就绪,就一直通知用户。在epoll底层表现为,一个epitem节点通过回调被连接到rdlist就绪队列中,只要该epitem对应的fd上IO事件还就绪着(比如对于读事件,socket接收缓冲区还有数据),就不会将其从rdlist中移除,因此用户每次调用epoll_wait都能获知该fd上的IO事件就绪。这是epoll的默认工作模式。
-
ET模式:只在fd的事件状态变化时通知用户一次。在epoll底层表现为,一个epitem节点通过回调被连接到rdlist就绪队列中,说明该epitem对应的fd上IO事件就绪,这里以读事件为例,用户调用epoll_wait后,获知该fd上的读事件就绪,用户可能把缓冲区中所有数据读完,也可能只读了一部分,epoll不管缓冲区中还有没有数据,即无论fd上的读事件是否依然就绪,fd对应的epitem直接从rdlist中移除,用户下次调用epoll_wait就读不到了。只有在下次新数据包到来时,ET才会再通知上层一次,这就是在“事件状态变化”时通知用户,即边缘触发。
🔎LT与ET的区别
从效率层面:
- 从效率角度来说,ET的效率高于LT。反复通知代表上层要多次调用epoll_wait来获取就绪事件信息,而一次通知只需要一次系统调用,系统调用从用户态到内核态开销较大,ET模式有效地减少了系统调用的次数。
ET与LT的区别更显著地体现在对上层的影响:
-
LT会反复通知事件就绪,这样一来,用户可能不会立刻处理事件,而是在需要的时候再处理。
-
ET只会在fd事件状态变化时通知用户一次,这样一来,就倒逼用户必须立刻处理完就绪事件,否则可能会错过事件。例如,fd读事件就绪,接收缓冲区上有2KB的数据,如果是ET模式通知用户,用户收到后就必须尽快将fd接收缓冲区上的所有数据读完,如果这次通知只读了1KB数据,且往后该fd没有新数据到来了,那么剩下的1KB数据就会丢失,因为ET模式不会再通知一次!
-
ET倒逼用户尽快取走数据,本质也是提高效率:使得底层的TCP接收窗口更大,从而在较大概率上使得对端的滑动窗口更大,提高通信效率。
如何设置ET模式?
设置fd的event为EPOLLET即可,这会让epoll对于该fd以ET模式工作。
如何保证一次处理完就绪事件?
以读事件为例,一次处理完读事件,就是一次性将接收缓冲区上的数据全部读完。调用read/recv接口循环读取fd上的数据,默认情况下,如果数据读完了,read/recv会阻塞等待,这样虽然能读完数据,但是上层无法获知。因此,必须使用非阻塞的方式读取数据!以非阻塞方式循环读取数据,当数据读完时,非阻塞read/recv不会挂起等待,而是以错误的形式返回,错误码为 EAGAIN or EWOULDBLOCK,这样一来,用户就可以通过对错误码的判断,获知数据是否读完了。对于写事件也是一样的,以非阻塞方式write/send,若发送缓冲区被写满了,表示写事件未就绪,错误码也会被设为EAGAIN or EWOULDBLOCK。
综上所述:使用 ET 模式的 epoll,需要将文件描述设置为非阻塞。 这个不是接口上的要求,而是"工程实践"上的要求,因为ET模式的机制总是要求程序员一次就绪响应就将事件处理完毕。
💭其它的理解细节:
事实上,LT也可以通过非阻塞的方式,通知一次就将所有数据取完,但由于LT是反复通知上层,就算不将数据一次读完,上层也不会错过就绪事件,只有ET的机制才倒逼用户必须立刻处理完就绪事件
epoll的应用场景
🔎并不是说使用epoll就一定是最高效的多路复用,还是要具体问题具体分析。epoll主要用于处理大规模、多并发、多连接的场景,特别是在高性能的网络服务器应用中。epoll在 Linux 上提供了一种高效的 I/O 多路复用机制,相较于select
和poll具有更好的性能和扩展性。而对于一些较小规模、连接较少的服务器,epoll带来的内存开销可能会比较大。因此,要根据具体问题和环境,选用具体的多路复用IO模型。
END…
相关文章:
【计算机网络】多路复用的三种方案
文章目录 1. selectselect函数select的工作特性select的缺点 2. pollpoll函数poll与select的对比 3. epollepoll的三个接口epoll的工作原理epoll的优点LT和ET模式epoll的应用场景 🔎Linux提供三种不同的多路转接(又称多路复用)的方案…...
供应链和物流的自动化新时代
今天,当大多数人想到物流自动化时,他们会想到设备。机器人、无人机和自主卡车运输在大家的谈话中占主导地位。全自动化仓库的视频在网上流传,新闻主播们为就业问题绞尽脑汁。这种炒作是不完整的,它错过了供应链和物流公司的机会。…...
Python与ArcGIS系列(九)自定义python地理处理工具
目录 0 简述1 创建自定义地理处理工具2 创建python工具箱0 简述 在arcgis中可以进行自定义工具箱,将脚本嵌入到自定义的可交互窗口工具中。本篇将介绍如何利用arcpy实现创建自定义地理处理工具以及创建python工具箱。 1 创建自定义地理处理工具 在arctoolbox中的自定义工具箱…...
Nginx部署前端项目
Nginx部署前端项目 1.在nginx官网http://nginx.org/en/download.html ,下载稳定版本: 2.解压后,点击根目录中的nginx.exe即可启动Nginx,或是在nginx安装目录中启动cmd并输入以下命令启动: nginx.exe 或 start nginx3…...
根据文件类型进行下载, 文档/图片
根据文件类型进行下载, 文档/图片 function loadFile(fileUrl, fileName) {if (isImageByExtension(fileUrl)) {try {downloadRes(fileUrl, fileName)} catch (error) {downloadFile(fileUrl, fileName)}} else {downloadRes(fileUrl, fileName)} } const downloadFile (file…...
赋范线性空间3
赋范线性空间三 文章目录 赋范线性空间三三、内积空间3.1 内积空间的定义和性质【定义】内积【定理】内积的性质——Schwarz不等式【定义】有内积导出的范数【定理】内积、由内积导出的范数 的性质 3.2 正交与正交系【定义】正交、正交补【定理】勾股定理在内积空间中的推广【定…...
XSLVGL2.0 User Manual 缩略图生成器(v2.0)
XSLVGL2.0 开发手册 XSLVGL2.0 User Manual 缩略图生成器 1、概述2、特性3、APIs3.1、xs_system_init_thumbnail3.2、xs_system_exit_thumbnail3.3、xs_system_get_thumbnail3.4、xs_system_thumbnail_on_cache_to_storage_defalut4、使用方法5、自定义缩略图生成方法1、概述 …...
练习八-利用有限状态机进行时序逻辑的设计
利用有限状态机进行时序逻辑的设计 1,任务目的:2,RTL代码,及原理框图3,测试代码,输出波形 1,任务目的: (1)掌握利用有限状态机实现一般时序逻辑分析的方法&am…...
WebAssembly照亮了 Web端软件的未来
WebAssembly的发展历程相对较短,但影响深远。WebAssembly 于 2015 年首次发布,先驱技术是来自Mozilla的asm.js和Google Native Client,最初的实现是基于asm.js的功能集。自2017年3月由WebAssembly创造的MVP的预览版发布以来,WebAs…...
PDF文件无密码,如何解密?
PDF文件有两种密码,一个打开密码、一个限制编辑密码,因为PDF文件设置了密码,那么打开、编辑PDF文件就会受到限制。想要解密,我们需要输入正确的密码,但是有时候我们可能会出现忘记密码的情况,或者网上下载P…...
搜维尔科技:Movella Xsens MVN LINK 实际应用,一镜到底!
搜维尔科技:Movella Xsens MVN LINK 实际应用,一镜到底!...
wsl安装ubuntu的问题点、处理及连接
WSL安装Ubuntu的参考链接 (41条消息) wsl报错:WslRegisterDistribution failed with error: 0x800701bc_yzpyzp的博客-CSDN博客_0x800701bc wsl (41条消息) 使用Ubuntu安装软件出现Unable to locate package错误解决办法_大灰狼学编程的博客-CSDN博客 手把手教你…...
Flutter在web项目中使用iframe
需要把原来的app项目移植到web上面,在app中使用的是flutter_inappwebview这个库,推荐使用这个库,因为修复了一部分webview_flutter中存在的问题 在web项目中flutter_inappwebview这个库不支持,所以需要自己封装一个web项目中的we…...
阿里云高校计划学生和教师完成认证领取优惠权益
阿里云高校计划学生和教师均可参与,完成学生认证和教师验证后学生可以免费领取300元无门槛代金券和3折优惠折扣,适用于云服务器等全量公共云产品,订单原价金额封顶5000元/年,阿里云百科aliyunbaike.com分享阿里云高校计划入口及学…...
劲松HPV防治诊疗中心提醒:做完HPV检查后,需留意这些事项!
在接受HPV检查后,有一些注意事项需要您注意。首先,要遵循医生的建议,并按照医生的指示进行后续治疗和随访。 其次,检查后可能会有些不适感,这是正常的现象,不必过于担心。但是,如果不适感持续加…...
InfoNCE Loss公式及源码理解
InfoNCE Loss公式及源码理解–从交叉熵损失谈起 当谈论到信息论中的损失函数时,InfoNCE(Noise Contrastive Estimation)和交叉熵损失都是两个关键的概念。它们不仅在衡量概率分布之间的差异方面发挥着重要作用,而且在深度学习的自…...
经典双指针算法试题(二)
📘北尘_:个人主页 🌎个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上,不忘来时的初心 文章目录 一、有效三角形的个数1、题目讲解2、讲解算法原理3、代码实现 二、查找总价格为目标值的两个商…...
MySQL -- DQL
1、select查询列和列名: --查询所有员工信息(*通配符,默认查询所有的列) select * from emp;--查询员工的姓名 select ename from emp;--查询员工的薪资 select sal from emp;--查询员工的姓名和薪资 select ename , sal from emp; select ename sal fr…...
高防CDN:保障网络安全的未来之路
在当前数字化飞速发展的时代,网络安全问题日益成为企业和个人关注的焦点。高防CDN(Content Delivery Network,内容分发网络)作为一种专注于防御网络攻击的解决方案,尽管在技术上表现卓越,但其普及却面临一系…...
使用wxPython和PyMuPDF合并PDF文档并自动复制到剪贴板
导语:处理大量的PDF文档可能会变得复杂和耗时。但是,使用Python编程和一些强大的库,如wxPython和PyMuPDF,可以使这个任务变得简单而高效。本文将详细解释一个示例代码,展示如何使用这些库来创建一个可以选择文件夹中的…...
简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...
论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)
笔记整理:刘治强,浙江大学硕士生,研究方向为知识图谱表示学习,大语言模型 论文链接:http://arxiv.org/abs/2407.16127 发表会议:ISWC 2024 1. 动机 传统的知识图谱补全(KGC)模型通过…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...
力扣热题100 k个一组反转链表题解
题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...
算术操作符与类型转换:从基础到精通
目录 前言:从基础到实践——探索运算符与类型转换的奥秘 算术操作符超级详解 算术操作符:、-、*、/、% 赋值操作符:和复合赋值 单⽬操作符:、--、、- 前言:从基础到实践——探索运算符与类型转换的奥秘 在先前的文…...
Vue3中的computer和watch
computed的写法 在页面中 <div>{{ calcNumber }}</div>script中 写法1 常用 import { computed, ref } from vue; let price ref(100);const priceAdd () > { //函数方法 price 1price.value ; }//计算属性 let calcNumber computed(() > {return ${p…...
flow_controllers
关键点: 流控制器类型: 同步(Sync):发布操作会阻塞,直到数据被确认发送。异步(Async):发布操作非阻塞,数据发送由后台线程处理。纯同步(PureSync…...
JS红宝书笔记 - 3.3 变量
要定义变量,可以使用var操作符,后跟变量名 ES实现变量初始化,因此可以同时定义变量并设置它的值 使用var操作符定义的变量会成为包含它的函数的局部变量。 在函数内定义变量时省略var操作符,可以创建一个全局变量 如果需要定义…...
Xcode 16 集成 cocoapods 报错
基于 Xcode 16 新建工程项目,集成 cocoapods 执行 pod init 报错 ### Error RuntimeError - PBXGroup attempted to initialize an object with unknown ISA PBXFileSystemSynchronizedRootGroup from attributes: {"isa">"PBXFileSystemSynchro…...
