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

【网络】poll 与epoll(原理、工作模式LT、ET)

文章目录

  • 1. poll
  • 2. epoll
  • 3. epoll原理
  • 4. epoll工作模式
    • 4.1 水平模式LT
    • 4.2 边缘模式ET

在这里插入图片描述
在前面用的select中,它的使用方式非常麻烦,而且能支持的文件描诉符太少了。
下面来介绍一下更加方便、高效的方式:

1. poll

poll函数接口:

include <poll.h>int poll(struct pollfd *fds, nfds_t nfds, int timeout);
// pollfd 结构
struct pollfd 
{int fd; /* file descriptor */short events; /* requested events */short revents; /* returned events */
};
  • fds 是一个 poll 函数监听的结构列表,每一个元素中,包含了三部分内容:文件描述符、监听的事件集合、返回的事件集合.
  • nfds 表示 fds 数组的长度.
  • timeout 表示 poll 函数的超时时间,单位是毫秒(ms).

events 和revents的取值如下:

在这里插入图片描述
在这里插入图片描述
常用的是POLLIN、POLLOUT

返回结果

  • 返回值小于 0, 表示出错;
  • 返回值等于 0, 表示 poll 函数等待超时;
  • 返回值大于 0, 表示 poll 由于监听的文件描述符就绪而返回
#pragma once
#include "Socket.hpp"
#include "Log.hpp"
#include <poll.h>
using namespace MyLogModule;
using namespace MySocketModule;#define NUM (sizeof(fd_set) * 8)
const int gdefaultfd = -1;
#define ARRAY_SIZE 64
class PollServer
{
private:std::unique_ptr<Socket> _listen_socket;int16_t _port;bool _isrunning;struct pollfd* _fd_array;	//fd数组public:PollServer(int16_t port): _port(port), _listen_socket(make_unique<TcpSocket>()),_fd_array(new pollfd[ARRAY_SIZE])	//给数组所开空间的大小,决定所能连接的fd的数量{}~PollServer(){}void Init(){_listen_socket->BuildTcpSocketMethod(_port);// 初始化辅助数组for (int i = 0; i < ARRAY_SIZE; i++){_fd_array[i].fd = gdefaultfd;_fd_array[i].events = 0;_fd_array[i].revents = 0;}// 将listen_socket添加至辅助数组_fd_array[0].fd = _listen_socket->GetSockfd();_fd_array[0].events |= POLLIN;}void Start(){_isrunning = true;while (_isrunning){int timeout = 1000;int n = poll(_fd_array, ARRAY_SIZE, timeout);switch (n){case 0:cout << "time out," << endl;break;case -1:cout << "select error" << endl;break;default:// 内核告诉用户,你关心的rfds中的fd,有哪些已经就绪了!!cout << "有事件就绪了..." << endl;Dispatcher();break;}}_isrunning = false;}void Accepter(){InetAddr client;// 此时accept就不会阻塞了int newfd = _listen_socket->AcceptOrDie(&client);if (newfd < 0)return;else{cout << "get a new link,fd:" << newfd << endl;//依旧需要遍历来添加新的fdint pos = -1;for (int j = 0; j < ARRAY_SIZE; j++){if (_fd_array[j].fd == gdefaultfd){pos = j;break;}}if (pos == -1){//可扩容cout << "服务器满载了..." << endl;close(newfd); // 关闭新连接}else{_fd_array[pos].fd = newfd; // 关心是否可读_fd_array[pos].events |= POLLIN;}}}void Recver(int who){char buf[1024];size_t n = recv(_fd_array[who].fd, buf, sizeof(buf) - 1, 0);if (n > 0){buf[n] = 0;cout << "Client# " << buf << endl;string str = "Echo#";str += buf;send(_fd_array[who].fd, str.c_str(), str.size(), 0); // bug}else if (n == 0){LOG(LogGrade::DEBUG) << "客户端退出了,fd:" << _fd_array[who].fd;close(_fd_array[who].fd);_fd_array[who].fd = gdefaultfd;_fd_array[who].events = _fd_array[who].revents = 0;}else{LOG(LogGrade::DEBUG) << "客户端读取出错了,fd:" << _fd_array[who].fd;close(_fd_array[who].fd);_fd_array[who].fd = gdefaultfd;_fd_array[who].events = _fd_array[who].revents = 0;}}void Dispatcher(){//依旧要轮巡检测fd数组for (int i = 0; i < ARRAY_SIZE; i++){if (_fd_array[i].fd == gdefaultfd)continue;// 判断是否是listen_socketif (_fd_array[i].fd == _listen_socket->GetSockfd()){// 判断listen_socket是否在rfds中if (_fd_array[i].revents & POLLIN){Accepter();}}else{// 普通fd就绪了// 可以读了,不用阻塞!if (_fd_array[i].revents & POLLIN){Recver(i);  //进行IO}}}}
};

poll 的优点:

  • 不同于 select 使用三个位图来表示三个 fdset 的方式, poll 使用一个 pollfd 的指针实现
  • pollfd 结构中包含了要监视的 event 和发生的 event,使输入参数与输出参数分离,无需重新设置,使用比 select 更方便.
  • poll 并没有最大数量限制 (但是数量过大后性能也是会下降)

poll 的缺点

  • poll 中监听的文件描述符数目增多时和 select 函数一样,poll 返回后,需要轮询 pollfd 来获取就绪的描述符
  • 每次调用 poll 都需要把大量的 pollfd 结构从用户态拷贝到内核中
  • 同时连接的大量客户端在一时刻可能只有很少的处于就绪状态,因此随着监视的描述符数量的增长,其效率也会线性下降

2. epoll

按照 man 手册的说法: 是为处理大批量句柄而作了改进的 poll。
它是在 2.5.44 内核中被引进的,几乎具备了之前所说的一切优点,被公认为 Linux2.6 下性能最好的多路 I/O 就绪通知方法

所需函数接口

  1. 创建epoll模型
#include <sys/epoll.h>
int epoll_create(int size);	//自从 linux2.6.8 之后,size 参数是被忽略的.
  • size:自从 linux2.6.8 之后,size 参数是被忽略的,随便填一个正整数
  • 用完之后, 必须调用 close()关闭.
  1. 事件注册
#include <sys/epoll.h>
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

它不同于 select()是在监听事件时告诉内核要监听什么类型的事件,而是在这里先注册要监听的事件类型.

  • 第一个参数是 epoll_create()的返回值(epoll 的句柄).
  • 第二个参数表示动作,用三个宏来表示
    • EPOLL_CTL_ADD: 注册新的 fd 到 epfd 中;
    • EPOLL_CTL_MOD:修改已经注册的 fd 的监听事件;
    • EPOLL_CTL_DEL:从 epfd 中删除一个 fd;
  • 第三个参数是需要监听的 fd.
  • 第四个参数是告诉内核需要监听什么事

其中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 可以是以下几个宏的集合:

  • EPOLLIN : 表示对应的文件描述符可以读 (包括对端 SOCKET 正常关闭);
  • EPOLLOUT : 表示对应的文件描述符可以写;
  • EPOLLPRI : 表示对应的文件描述符有紧急的数据可读 (这里应该表示有带外数据到来);
  • EPOLLERR : 表示对应的文件描述符发生错误;
  • EPOLLHUP : 表示对应的文件描述符被挂断;
  • EPOLLET : 将 EPOLL 设为边缘触发(Edge Triggered)模式, 这是相对于水平触发(Level Triggered)来说的.
  • EPOLLONESHOT: 只监听一次事件, 当监听完这次事件之后, 如果还需要继续监听这个 socket 的话, 需要再次把这个 socket 加入到 EPOLL 队列里.
  1. 收集就绪事件
#include <sys/epoll.h>
int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);

收集在 epoll 监控的事件中已经发送的事件.

  • 参数 epoll_event 是分配好的 epoll_event 结构体数组,它是输出参数表示哪些fd的哪些事件就绪了
  • epoll 将会把发生的事件赋值到 events 数组中 (events 不可以是空指针,内核只负责把数据复制到这个 events 数组中).
  • maxevents 告之内核这个 events 有多大, 这个 maxevents 的值不能大于创建epoll_create()时的 size.
  • 参数 timeout 是超时时间 (毫秒, 0 会立即返回, -1 是永久阻塞).
  • 如果函数调用成功 大于0,返回对应 I/O 上已准备好的文件描述符数目, 若返回 0 表示已超时,返回小于 0 表示函数失败

使用案例:

#pragma once
#include "Socket.hpp"
#include "Log.hpp"
#include <sys/epoll.h>
using namespace MyLogModule;
using namespace MySocketModule;const int gdefaultfd = -1;
#define ARRAY_SIZE 64class EpollServer
{
private:std::unique_ptr<Socket> _listen_socket;int16_t _port;bool _isrunning;int _epollfd;       //epoll模型所对应的fdstruct epoll_event *_ready_events;  //接收就绪事件的数组
public:EpollServer(int16_t port): _port(port), _listen_socket(make_unique<TcpSocket>()),_ready_events(new epoll_event[ARRAY_SIZE]){}~EpollServer(){}void Init(){_listen_socket->BuildTcpSocketMethod(_port);//1. epoll模型创建成功_epollfd = epoll_create(128);//ince Linux 2.6.8, the size argument is ignored,参数随便填一个 正整数!if(_epollfd < 0){LOG(LogGrade::ERROR) << "epoll_create fail";exit(EPOLL_CREATE_ERR);}//2. 将listen_socket添加到模型中struct epoll_event ev;ev.data.fd = _listen_socket->GetSockfd();ev.events = EPOLLIN;int n = epoll_ctl(_epollfd,EPOLL_CTL_ADD,_listen_socket->GetSockfd(),&ev);if(n < 0){LOG(LogGrade::ERROR) << "epoll_ctl fail";exit(EPOLL_CTRL_ERR);}}void Start(){_isrunning = true;while (_isrunning){int timeout = 1000;//3. 等待int n = epoll_wait(_epollfd, _ready_events, ARRAY_SIZE, timeout);switch (n){case 0:cout << "time out," << endl;break;case -1:cout << "select error" << endl;break;default:cout << "有事件就绪了....." << endl;//将就绪事件的个数传递,不做无效的遍历Dispatcher(n);break;}}_isrunning = false;}void Accepter(){InetAddr client;// 此时accept就不会阻塞了int newfd = _listen_socket->AcceptOrDie(&client);if (newfd < 0)return;else{//将fd添加到epoll模型中struct epoll_event ev;ev.data.fd = newfd;ev.events = EPOLLIN;int n = epoll_ctl(_epollfd, EPOLL_CTL_ADD, newfd, &ev);if(n < 0){LOG(LogGrade::ERROR) << "epoll_ctl fail";close(newfd);}LOG(LogGrade::ERROR) << "epoll_ctl success";}}void Recver(int fd){char buf[1024];size_t n = recv(fd, buf, sizeof(buf) - 1, 0);   //bugif (n > 0){buf[n] = 0;cout << "Client# " << buf << endl;string str = "Echo#";str += buf;send(fd,str.c_str(),str.size(), 0);   //bug}else if (n == 0){LOG(LogGrade::DEBUG) << "客户端退出了,fd:" << fd;//epoll_ctl规定,传入的fd必须是非法的,因此需要先移除,后关闭int n = epoll_ctl(_epollfd, EPOLL_CTL_DEL, fd, nullptr);if(n < 0){LOG(LogGrade::ERROR) << "epoll_ctl fail";exit(EPOLL_CTRL_ERR);}close(fd);  //后关闭}else{LOG(LogGrade::DEBUG) << "客户端读取出错了,fd:" << fd;int n = epoll_ctl(_epollfd, EPOLL_CTL_DEL, fd, nullptr);if(n < 0){LOG(LogGrade::ERROR) << "epoll_ctl fail";exit(EPOLL_CTRL_ERR);}//epoll_ctl规定,传入的fd必须是非法的,因此需要先移除,后关闭close(fd);}}void Dispatcher(int readynum){//数组中全是就绪事件,没有无效的遍历for (int i = 0; i < readynum;i++){// 判断是否是listen_socketif (_ready_events[i].data.fd == _listen_socket->GetSockfd()){// 判断listen_socket是否在返回的事件中if (_ready_events[i].events & EPOLLIN){Accepter();}}else{// 普通fd就绪了if (_ready_events[i].events & EPOLLIN){//读事件就绪Recver(_ready_events[i].data.fd);  //进行IO}}}}
};

3. epoll原理

在这里插入图片描述
当某一进程调用 epoll_create 方法时, Linux 内核会创建一个 eventpoll 结构体, 这个结构体中有两个成员与 epoll 的使用方式密切相关.

struct eventpoll{//..../*红黑树的根节点, 这颗树中存储着所有添加到 epoll 中的需要监控的事件*/struct rb_root rbr;/*双链表中则存放着将要通过 epoll_wait 返回给用户的满足条件的事件*/struct list_head rdlist;//....
};

红黑树上的一个节点,代表内核要为用户关心哪个fd上的哪些事件(epoll_ctl本质在修改红黑树),该红黑树就相当于select 与poll 中的辅助数组,现在这个数据结构不需要调用者维护了,由内核维护。

就绪链表:内核告诉用户,哪个fd上的哪些事件已经就绪了(epoll_wait本质是从该链表中拿取的fd)

每一个 epoll 对象都有一个独立的 eventpoll 结构体, 用于存放通过 epoll_ctl 方法向 epoll对象中添加进来的事件.

  • 这些事件都会挂载在红黑树中, 如此, 重复添加的事件就可以通过红黑树而高效的识别出来
  • 所有添加到 epoll 中的事件都会与设备(网卡)驱动程序建立回调关系,也就是说,当响应的事件发生时会调用这个回调方法.
  • 这个回调方法在内核中叫 ep_poll_callback,它会将发生的事件添加到 rdlist 双链表中.
  • 在 epoll 中, 对于每一个事件, 都会建立一个 epitem 结构体
  • 调用 epoll_wait 检查是否有事件发生时,只需要检查 eventpoll 对象中的rdlist 双链表中是否有 epitem 元素即可O(1).
  • 如果 rdlist 不为空,则把发生的事件复制到用户态,同时将事件数量返回给用户,这个操作的时间复杂度O(n)
struct epitem{struct rb_node rbn;//红黑树节点struct list_head rdllink;//双向链表节点struct epoll_filefd ffd; //事件句柄信息struct eventpoll *ep; //指向其所属的 eventpoll 对象struct epoll_event event; //期待发生的事件类型
}

如何理解epoll_create返回的是一个文件描诉符呢?

eventepoll 被struct file中的void *private_data指针指向,通过文件描述符,就可以找到epoll模型,进而找到红黑树、就绪队列

epoll为什么高效?

  1. 原理层面:用户将要关心的fd和事件注册进去后,OS自己调用回调函数驱动;事件就绪后,将其结构加入到就绪队列中(不需要轮询检测了,OS自动将其加入到就绪队列中,只需要看就绪队列即可
  2. 接口层面:epoll返回给用户就绪事件时,直接将就绪的事件返回,不做无效的拷贝;

epoll 的优点(和 select 的缺点对应)

  • 接口使用方便:虽然拆分成了三个函数,但是反而使用起来更方便高效,不需要每次循环都设置关注的文件描述符,也做到了输入输出参数分离开
  • 数据拷贝轻量只在合适的时候调用 EPOLL_CTL_ADD 将文件描述符结构拷贝到内核中, 这个操作并不频繁,用户到内核的拷贝少(select/poll 都是每次循环都要进行拷贝,涉及太多用户到内核的拷贝)
  • 事件回调机制: 避免使用遍历,而是使用回调函数的方式,将就绪的文件描述符结构加入到就绪队列中,epoll_wait 返回直接访问就绪队列就知道哪些文件描述符就绪,这个操作时间复杂度 O(1),即使文件描述符数目很多,效率也不会受到影响.
  • 没有数量限制:文件描述符数目无上限

4. epoll工作模式

poll 有 2 种工作方式:水平触发(level triggered)边缘触发(edge triggered)

假如你正在打游戏,进入关键时刻,你妈饭做好了,喊你吃饭的时候有两种方式:

  • 如果你妈喊你一次,你没动,那么你妈会继续喊你第二次,第三次…,直到你过来吃饭(亲妈,水平触发)
  • 如果你妈喊你一次,你没动,你妈就不管你了(后妈,边缘触发)

select、poll的工作模式就是 LT,epoll默认状态下就是 LT 工作模式

4.1 水平模式LT

水平触发工作模式

  • 当 epoll 检测到 socket 上事件就绪的时候,可以不立刻进行处理,或者只处理一部分.
  • 假如socket 的另一端被写入了 10KB 的数据,由于只读了 1K 数据,缓冲区中还剩 9K 数据;在第二次调用epoll_wait 时,epoll_wait 仍然会立刻返回并通知 socket读事件就绪就绪数据,会一直在rdlist中,除非把数据取完,否则,该节点一直存在,epoll_wait就一直返回
  • 直到缓冲区上所有的数据都被处理完,epoll_wait 才不会立刻返回.
  • 支持阻塞读写和非阻塞读写

4.2 边缘模式ET

边缘触发工作模式:如果我们在第1步将 socket 添加到 epoll 描述符的时候若使用了 EPOLLET 标志,epoll 进入 ET 工作模式

  • 当 epoll 检测到 socket 上事件就绪时,必须立刻处理
  • 假如socket 的另一端被写入了 10KB 的数据,虽然只读了 1K 的数据,缓冲区还剩 9K 的数据,在第二次调用epoll_wait 的时候,epoll_wait 不会再返回了
  • 也就是说,ET 模式下,文件描述符上的事件就绪后,只有一次处理机会。 epol_wait取走了就绪节点,该节点在rdlist中立马移除,除非又有数据从网络传递到节点的缓冲区,否则,不再通知(即便缓冲区中数据没有取完)
  • 只支持非阻塞的读写

ET模式更加高效的原因:

  1. epoll_wait 返回的次数少了很多(内核到用户的拷贝变少了),因为不做重复通知,一旦通知,数据必须全部取完(倒逼程序猿取完)
  2. 上层取完了,可以给通信的对端通告一个更大的接收窗口,对端滑动窗口也就更大,网络IO的吞吐量也就大了。

ET模式是有代价的:

  • 一旦数据就绪,要读取,必须全部取完;
  • 如果不取完,且该fd没有数据再来了,则会造成上次未取完的数据丢失

你怎么保证能取完呢?(循环读 + 非阻塞

循环读取,一旦循环读取,就必须是非阻塞的 (O_NONBLOCK);如果在读取时阻塞了,会导致服务器无法处理其他事件,服务器的性能会严重下降,甚至可能完全卡住

epoll 的使用场景:
epoll 的高性能,是有一定的特定场景的,如果场景选择的不适宜, epoll 的性能可能适得其反

  • 对于多连接,且多连接中只有一部分连接比较活跃时,比较适合使用 epoll;(若连接都是活跃的,则可以使用多进程/线程 + epoll的方式)

例如,典型的一个需要处理上万个客户端的服务器,例如各种互联网 APP 的入口服务器,这样的服务器就很适合 epoll.

  • 对于少数连接,如果只是系统内部,服务器和服务器之间进行通信,只有少数的几个连接,这种情况下用epoll 就并不合适
  • 具体要根据需求和场景特点来决定使用哪种 IO 模型

在这里插入图片描述

相关文章:

【网络】poll 与epoll(原理、工作模式LT、ET)

文章目录 1. poll2. epoll3. epoll原理4. epoll工作模式4.1 水平模式LT4.2 边缘模式ET 在前面用的select中&#xff0c;它的使用方式非常麻烦&#xff0c;而且能支持的文件描诉符太少了。 下面来介绍一下更加方便、高效的方式: 1. poll poll函数接口&#xff1a; include <…...

DeepIn Wps 字体缺失问题

系统缺失字体 Symbol 、Wingdings 、Wingdings2、Wingdings3、MT—extra 字体问题 问了下DeepSeek 在应用商店安装或者在windows 里面找 装了一个GB-18030 还是不行 在windows里面复制了缺失的字体 将字体复制到DeepIn 的字体目录&#xff08;Ubuntu 应该也是这个目录&am…...

Spring有哪些缺点?

大家好&#xff0c;我是锋哥。今天分享关于【Spring有哪些缺点?】面试题。希望对大家有帮助&#xff1b; Spring有哪些缺点? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Spring是一个非常流行的Java框架&#xff0c;提供了丰富的功能和灵活的配置选项&#xf…...

使用Dockerfile打包java项目生成镜像部署到Linux_java项目打docker镜像的dockerfile

比起容器、镜像来说&#xff0c;Dockerfile 非常普通&#xff0c;它就是一个纯文本&#xff0c;里面记录了一系列的构建指令&#xff0c;比如选择基础镜像、拷贝文件、运行脚本等等&#xff0c;每个指令都会生成一个 Layer&#xff0c;而 Docker 顺序执行这个文件里的所有步骤&…...

蓝桥杯刷题周计划(第二周)

目录 前言题目一题目代码题解分析 题目二题目代码题解分析 题目三题目代码题解分析 题目四题目代码题解分析 题目五题目代码题解分析 题目六题目代码题解分析 题目七题目代码题解分析 题目八题目题解分析 题目九题目代码题解分析 题目十题目代码题解分析 题目十一题目代码题解分…...

03 | fastgo 项目规范及目录结构介绍

提示&#xff1a; 所有体系课见专栏&#xff1a;Go 项目开发极速入门实战课&#xff1b;欢迎加入我的训练营&#xff1a;云原生AI实战营&#xff0c;一个助力 Go 开发者在 AI 时代建立技术竞争力的实战营。 为了让你更好的学习本课程。本节课&#xff0c;我来简单介绍下 fastgo…...

K8S学习之基础二十三:k8s的持久化存储之nfs

K8S持久化存储之nfs ​ 在 Kubernetes (k8s) 中使用 NFS&#xff08;Network File System&#xff09;作为存储解决方案是一种常见的方式&#xff0c;特别是在需要共享存储的场景中。以下是关于如何在 Kubernetes 中使用 NFS 存储的详细说明&#xff1a; 1. 准备 NFS 服务器 …...

CTF代码学习日记 Python

os模块 在Python中&#xff0c;os是一个内置的标准模块&#xff0c;主要用于与操作系统进行交互&#xff0c;提供了许多操作文件、目录、进程等的功能。 例如&#xff1a; os.mkdir()用于创建新目录os.rmdir()用于删除空目录os.listdir()可以列出指定目录下的所有文件和目录…...

存储优化(protobuf与mmkv)

存储优化&#xff08;protobuf与mmkv&#xff09; 在Android应用开发中&#xff0c;数据存储是一个基础且关键的环节。随着应用功能的日益复杂&#xff0c;数据量的增加&#xff0c;传统的存储方式如SharedPreferences、SQLite等在性能上的局限性逐渐显现。本文将深入探讨两种…...

MTK Android12 添加GMS后,报“设备未经过play保护认证“问题

文章目录 问题解决 问题 在MTK平台的Android12机柜上面&#xff0c;客户要求安装GMS。安装后&#xff0c;打开发现报"设备未经过play保护认证"问题&#xff0c;无法使用。解决 路径&#xff1a;/build/make/tools/buildinfo.sh diff --git a/build/make/tools/bui…...

自定义Linux网络协议的开发与测试

在当今快速发展的技术领域中,定制化网络协议可以为特定的应用场景提供灵活而强大的解决方案。本文将详细介绍如何在Linux系统上开发一个自定义网络协议,并编写相应的用户空间程序进行测试。所有步骤基于2025年3月11日的时间点完成。 开发自定义协议内核模块 定义协议和实现…...

Ubuntu 24.04 安装与配置 JetBrains Toolbox 指南

&#x1f4cc; 1. JetBrains Toolbox 介绍 JetBrains Toolbox 是 JetBrains 开发的工具管理器&#xff0c;可用于安装、更新和管理 IntelliJ IDEA、PyCharm、WebStorm、CLion 等。本指南记录了 JetBrains Toolbox 在 Ubuntu 24.04 上的 安装、路径调整、权限管理 及 遇到的问题…...

说一下spring的事务隔离级别?

大家好&#xff0c;我是锋哥。今天分享关于【说一下spring的事务隔离级别&#xff1f;】面试题。希望对大家有帮助&#xff1b; 说一下spring的事务隔离级别&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Spring的事务隔离级别是指在数据库事务管理中…...

【社区投稿】深入再谈智能指针、AsRef引用与Borrow借用

深入再谈智能指针、AsRef引用与Borrow借用 这是一个具有深度的技术主题。每次重温其理论知识&#xff0c;都会有新的领悟。大约 2 年前&#xff0c;我曾就这一技术方向撰写过另一篇短文《从类型转换视角&#xff0c;浅谈Deref<Target T>, AsRef<T>, Borrow<T&g…...

C++ Primer Plus第十二章课后习题总结

1. 对于下面的类声明&#xff1a; class Cow {char name[20];char * hobby;double weight;public:Cow();Cow(const char * nm, const char * ho, double wt);Cow(const Cow c&);~Cow();Cow & operator(const Cow & c);void ShowCow() const; // display all cow d…...

Xavier 初始化:深度网络权重初始化的经典之作

Xavier 初始化&#xff1a;深度网络权重初始化的经典之作 发音&#xff1a;美 [zeɪvjər] n.泽维尔&#xff08;男子名&#xff09; 在深度学习的发展历程中&#xff0c;权重初始化对神经网络训练的成功至关重要。随机初始化的简单方法在浅层网络中尚可&#xff0c;但在深层…...

【量化策略】动量反转策略

【量化策略】动量反转策略 &#x1f680;量化软件开通 &#x1f680;量化实战教程 技术背景与应用场景 动量反转策略是一种基于市场行为分析的量化交易策略&#xff0c;它假设股票价格在经历一段时间的持续上涨或下跌后&#xff0c;会出现反转。这种策略适用于那些希望通过…...

菜鸟之路Day23一一JavaScript 入门

菜鸟之路Day23一一JavaScript 入门 作者&#xff1a;blue 时间&#xff1a;2025.3.10 文章目录 菜鸟之路Day23一一JavaScript 入门0.概述1.JS的引入方式2.JS的基础语法2.1输出语句2.2变量2.3数据类型2.4运算符2.5类型转换 3.函数4.JS对象4.1Array对象4.2String对象4.3Js自定义…...

FreeSWITCH 简单图形化界面40 - 使用mod_curl模块进行http请求

FreeSWITCH 简单图形化界面40 - 使用mod_curl模块进行http请求 0、界面预览00、简介1、编译安装1.1 编辑模块配置文件 2、使用2.1 拨号规则GET 请求POST 请求JSON 数据 2.2 Lua 脚本GET 请求POST 请求JSON 数据 3 、示例3.1 示例 1&#xff1a;提交 CDR 到第三方接口3.2 示例 2…...

TCP/IP原理详细解析

前言 TCP/IP是一种面向连接&#xff0c;可靠的传输&#xff0c;传输数据大小无限制的。通常情况下&#xff0c;系统与系统之间的http连接需要三次握手和四次挥手&#xff0c;这个执行过程会产生等待时间。这方面在日常开发时需要注意一下。 TCP/IP 是互联网的核心协议族&…...

HTTP与HTTPS的深度解析:技术差异、安全机制及应用场景

引言 HTTP&#xff08;超文本传输协议&#xff09;作为互联网通信的核心协议&#xff0c;自1991年诞生以来&#xff0c;经历了从HTTP/1.0到HTTP/3的多次迭代。然而&#xff0c;随着网络安全威胁的升级&#xff0c;纯HTTP协议因缺乏加密机制逐渐暴露其局限性。本文将重点解析HT…...

DrissionPage:更高效的动态爬虫实践(实例)

场景分析 代码重构对比 原Requests方案痛点 DrissionPage方案优势 重构后完整代码 关键技术点解析 1. 会话保持与指纹模拟 2. 智能请求重试 3. 反反爬策略 4. 混合模式扩展 性能对比测试 适用场景建议 常见问题解决 场景分析 原代码通过Requests直接调用B站API接…...

Triplet Loss原理及 Python实现

Triplet loss最初是谷歌在 FaceNet: A Unified Embedding for Face Recognition and Clustering 论文中提出的&#xff0c;可以学到较好的人脸的embedding Triplet Loss 是一种用于训练特征嵌入&#xff08;feature embedding&#xff09;的损失函数&#xff0c;广泛应用于人脸…...

2025人工智能AI新突破:PINN内嵌物理神经网络火了

最近在淘金的时候发现基于物理信息的神经网络&#xff08;简称PINN&#xff09;也是个研究热点&#xff0c;遂研读了几篇经典论文&#xff0c;深觉这也是个好发论文的方向&#xff0c;所以火速整理了一些个人认为很值得一读的PINN论文和同学们分享。 为了方面同学们更好地理解…...

深入探索Matter协议:开发Matter智能家居设备的基本步骤

随着家居智能化程度的提高&#xff0c;智能家居设备之间相互连接的网络虽然提升了家庭便利性&#xff0c;但也变得越来越复杂&#xff0c;难以管理。将亚马逊Alexa、Ring门铃、谷歌Nest Hub和苹果HomeKit等各种设备连接起来&#xff0c;并确保这些不同设备和操作系统能够良好地…...

搜广推校招面经四十五

快手主站推荐算法 这个是做因果选券的&#xff0c;如果大家的工作和这个有关&#xff0c;可以看看 一、有没有分析特征对各个的贡献度&#xff0c;怎么做&#xff1f; 传统的特征重要度衡量方法&#xff0c;就不介绍了。什么基于树模型的、SHAP值、LIME等。 但其实实际工程中…...

python之replace,strip,split命令

1. replace() 方法 功能&#xff1a;替换字符串中的指定子串 语法&#xff1a;str.replace(old, new[, count]) 特点&#xff1a; 全部替换&#xff08;默认&#xff09;或指定替换次数区分大小写返回新字符串&#xff0c;原字符串不变 示例&#xff1a; text "Hello…...

C语言处理字符串的十个函数(附带大量实例)

C语言的字符串处理函数主要集中在 <string.h> 头文件中&#xff0c;使用这些函数前必须包含该头文件。 字符串处理函数操作的对象通常是字符串&#xff08;以 \0 结尾的字符数组&#xff09;&#xff0c;它们极大地方便了文本处理任务。 以下是我们将要讲解的主要函数&…...

【10】单片机编程核心技巧:指令周期与晶振频率

【10】单片机编程核心技巧&#xff1a;指令周期与晶振频率 &#x1f31f; 核心概念 单片机的运算速度与时间控制&#xff0c;本质上由 指令周期 和 晶振频率 共同决定。理解这两者的关系&#xff0c;是掌握单片机底层控制的关键。 &#x1f4cc; 1. 节拍与指令周期 &#x1…...

GitLab的Dockerfile 追踪

为了在 GitLab 上准备每个平台的 Docker 镜像文件&#xff0c;并实现完整的 Dockerfile 追踪&#xff0c;可以按照以下步骤进行操作&#xff1a; 项目准备 首先&#xff0c;确保你有一个 GitLab 项目&#xff0c;并且本地已经克隆了该项目的仓库。如果还没有项目&#xff0c;可…...

HTML基础

前言 什么是 HTML&#xff1f; HTML 是一种用于创建网页结构的标记语言&#xff0c;通过标签&#xff08;Tag&#xff09;定义内容的结构和呈现方式。 浏览器解析 HTML 文档后&#xff0c;将其渲染为可视化网页。 一、HTML 语法 1. HTML 基本骨架 所有 HTML 文档必须包含以下…...

静态时序分析:无法满足的生成时钟(TIM-255警告、UITE-461或PTE-075错误)

相关阅读 静态时序分析https://blog.csdn.net/weixin_45791458/category_12567571.html?spm1001.2014.3001.5482 在阅读本文前&#xff0c;强烈建议首先阅读介绍生成时钟的文章&#xff0c;尤其是其中关于时钟极性和反相的相关内容。 静态时序分析&#xff1a;SDC约束命令cr…...

SpringBoot日常:集成shareingsphere-jdbc

文章目录 pom依赖application.yml配置log4j2.xml实体类MapperServicecontroller调用插入接口调用查询接口 本章内容我们来聊聊如何将shareingsphere-jdbc集成到我们自己的springboot项目中&#xff0c;本章采用的shareingsphere-jdbc版本是5.1.2&#xff0c;springboot项目是2.…...

Java 生成图形验证码

一、图形验证码的意义 图形验证码是一种广泛应用于互联网领域的安全验证机制&#xff0c;它通过向用户展示包含字符、数字、图形等信息的图片&#xff0c;要求用户正确识别并输入其中的内容&#xff0c;以此来区分用户是人类还是机器程序。图形验证码具有多方面重要意义&#…...

nextjs15简要介绍以及配置eslint和prettier

目录 一、Next.js 何时使用服务器端渲染&#xff08;SSR&#xff09;&#xff1f;何时使用静态生成&#xff08;SSG&#xff09;&#xff1f; 1、服务器端渲染&#xff08;SSR - getServerSideProps&#xff09; 2、 静态生成&#xff08;SSG - getStaticProps&#xff09; …...

插入排序算法优化

一 插入排序概述 插入排序是稳定的原地排序算法,核心思想是逐步构建有序序列。对于未排序部分的每个元素,在已排序序列中从后向前扫描,找到合适位置插入。时间复杂度为: 最优:O(n)(已有序) 最差:O(n^2)(完全逆序) 平均:O(n^2) 二 二分查找优化(减少比较次数)…...

python学智能算法(七)|KNN邻近算法

【1】引言 前述学习进程中&#xff0c;已经了解了一些非常经典的智能算法&#xff0c;相关文章包括且不限于&#xff1a; python学智能算法&#xff08;三&#xff09;|模拟退火算法&#xff1a;深层分析_模拟退火 动画演示-CSDN博客 python学智能算法&#xff08;四&#x…...

LabVIEW闭环控制系统硬件选型与实时性能

在LabVIEW闭环控制系统的开发中&#xff0c;硬件选型直接影响系统的实时性、精度与稳定性。需综合考虑数据采集速度&#xff08;采样率、接口带宽&#xff09;、计算延迟&#xff08;算法复杂度、处理器性能&#xff09;、输出响应时间&#xff08;执行器延迟、控制周期&#x…...

JavaScript(Web APIs)

这个阶段两天也能看完 目录 壹_DOM-获取元素 00、获取DOM元素&#xff08;根据CS选择器来获取DOM元素&#xff09; 01、修改元素内容 02、修改CSS 03、H5自定义属性 04、定时器 贰_DOM-事件基础 00、事件监听 01、事件类型 02、事件对象 03、环境对象 04、回调函数 叁_DOM-事…...

创建Electron35 + vue3 + electron-builder项目,有很过坑,记录过程

环境&#xff1a; node v20.18.0 npm 11.1.0 用到的所有依赖&#xff1a; "dependencies": {"core-js": "^3.8.3","vue": "^3.2.13","vue-router": "^4.5.0"},"devDependencies": {"ba…...

机器视觉条形光源应用解析

在机器视觉中,条形光源是一种常见的照明设备,通过其特殊的形状和光路设计,能够有效解决检测中的光照均匀性、反光抑制、对比度增强等问题。以下是关于条形光源的详细解析: 1. 条形光源的基本结构与类型 结构:由多个LED灯珠沿直线或弧形排列,通常封装在长条形外壳中,可单…...

苹果商店上架流程,app上架发布流程

苹果商店地址 https://appstoreconnect.apple.com/login 其他地址:开发 - Apple Developer 1.更新代码 将项目的代码更新到最新,更新成功后右下角会给出提示 2.打开模拟器 鼠标右键可以选择设备(Device) 3.测试运行 如下图可以看到已经识别到设备了,点击运行即可,运行到模…...

大数据技术在土地利用规划中的应用分析

大数据技术在土地利用规划中的应用分析 一、引言 土地利用规划是对一定区域内的土地开发、利用、整治和保护所作出的统筹安排与战略部署,对于实现土地资源的优化配置、保障社会经济的可持续发展具有关键意义。在当今数字化时代,大数据技术凭借其海量数据处理、高效信息挖掘等…...

【Axure资料】110套优质可视化大屏模板+图表组件+科技感元件等

本作品集包含110套高保真可视化大屏模板&#xff0c;以及丰富的图表组件和科技感元件&#xff0c;旨在满足各行业对数据可视化展示的需求。所有模板和组件均基于Axure RP 9软件设计&#xff0c;确保高质量的交互体验和视觉效果。 作品类型&#xff1a;Axure原型模板 兼容版本&…...

TCP-IP协议通信模型

一、TCP/IP协议概述 TCP/IP协议即传输控制协议/互联网协议&#xff0c;也被称为网络通讯协议。它包含了一系列构成互联网基础的网络协议&#xff0c;是Internet的核心协议。 二、TCP/IP协议通信模型 文件中提到了TCP/IP协议通信模型&#xff0c;但未详细展开其具体层次结构和…...

VMware下载安装Ubuntu详解

一、Linux简介 1、不同领域的主流操作系统 桌面操作系统服务器操作系统移动设备操作系统嵌入式操作系统 1.1、桌面操作系统 Windows&#xff08;用户数量最多&#xff09;Mac OS&#xff08;苹果电脑操作系统&#xff09;Linux&#xff08;用户数量少&#xff09; 1.2、服…...

wpf label 内容绑定界面不显示

<Label Content"{Binding LabelText}" /> ... public string LabelText {get;set;}后端改变值后,界面内容并不显示 查看资料后改动如下 private string _labelText; public string LabelText{get { return _labelText; }set { _labelText value; OnPropertyCh…...

VC++ 获取目的IP的路由

GetBestRoute 函数获取到目的IP的最佳匹配路由。 第一个参数为&#xff1a;destination&#xff08;目的IP&#xff09; 第二个参数为&#xff1a;source&#xff08;源IP&#xff09; 通常不需要指定第二个source&#xff0c;这个一般用来匹配具体某一个网卡接口路由的&…...

海外跨境专线是什么?如何搭建海外跨境专线?

网络跨境专线——这一名词你听说过吗&#xff1f;如果你在跨境经济、国际贸易或网络通信领域工作&#xff0c;那它一定是你日常工作的一个重要话题。今天我们就来聊聊网络跨境专线的概念和搭建方法&#xff0c;希望能够为你在这一领域的探索提供一些帮助。 一、什么是网络跨境…...

【神经网络】python实现神经网络(二)——正向推理的模拟演练

一.神经网络假设 在开始讲解之前,首先我们假设有这样一套神经网络,一共有三层: 其中,关于神经网络的权重、偏置的符号定义如下(如果不知道什么是权重和偏置,可以参考我之前写过的一篇文章:【机器学习】机器学习是什么意思): 以下文章将沿用以上这个设…...