【文末送书】计算机网络 | IO多路转接技术 | poll/epoll详解

欢迎关注博主 Mindtechnist 或加入【Linux C/C++/Python社区】一起学习和分享Linux、C、C++、Python、Matlab,机器人运动控制、多机器人协作,智能优化算法,滤波估计、多传感器信息融合,机器学习,人工智能等相关领域的知识和技术。
IO多路转接技术 —— poll/epoll详解
- 1. poll详解
- 2. epoll详解
- (1)API介绍
- (2)epoll树
- (3)epoll模型
- (4)epoll的三种工作模式
- (5)文件描述符1024限制
- 图书推荐 -《构建高性能嵌入式系统》
🎉🎉🎉🎉🎉 重磅福利 🎉🎉🎉🎉🎉🎉
🎉本次送1本书 ,评论区抽1位小伙伴送书🎉
🎉活动时间:截止到 2023-11-30 10:00:00🎉
🎉抽奖方式:评论区随机抽奖。
🎉参与方式:关注博主、点赞、收藏,评论。
❗注意:一定要关注博主,不然中奖后将无效!
🎉通知方式:通过私信联系中奖粉丝。
💡提示:有任何疑问请私信公粽号 《机器和智能》
专栏:《Linux从小白到大神》《网络编程》
1. poll详解
-
函数原型
int poll(struct pollfd *fd, nfds_t nfds, int timeout); -
函数参数
-
fd:数组的地址,struct pollfd all[120]; 其中struct pollfd结构体如下
struct pollfd {int fd; /* 文件描述符 */short events; /* 等待的事件 */short revents; /* 实际发生的事件 */ };结构体红各项含义如下:
-
文件描述符fd:表示要坚持测的fd,通过 open(“a.txt”, O_wronly | O_append); 获得。
-
events:要等待的事件

-
revents:实际发生的事件,它是内核给的反馈,在select的时候,会有一个备份来供内核修改并传出。
-
-
nfds:数组的最大长度, 数组中最后一个使用的元素下标+1
-
- 内核会轮询检测fd数组的每个文件描述符
-
timeout:
-
- -1:永久阻塞
- 0:调用完成立即返回
- >0:等待的时长毫秒
-
-
函数返回值:IO发生变化的文件描述符的个数。
2. epoll详解
(1)API介绍
int epoll_create(int size);
- 函数功能:生成一个epoll专用的文件描述符,实际上就是生成一个epoll树的根结点。
- 函数参数:size,epoll树上能挂的最大文件描述符数量。表示我想在这个树节点上挂size个节点,假如实际上的节点大于size的话epoll会自动扩展,所以这个大小可以随便传,不用太在意。但是这个扩展也是有上限的,如果电脑内存是1G,那么扩展的上限是10万(2G就是20万。。。通过加内存可以扩大上限)。
- 函数返回值:函数返回值是树的根节点,在后面用到epft参数的时候,都是指这个返回值,也就是树的根节点。

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
-
函数功能:用于控制某个epoll文件描述符事件,可以注册、修改、删除。
-
函数参数:
-
epfd:epoll_create()函数生成的专用文件描述符。
-
op:
- EPOLL_CTL_ADD —— 注册
- EPOLL_CTL_MOD —— 修改
- EPOLL_CTL_DEL —— 删除
-
fd:关联的文件描述符
-
event:告诉内核要监听什么事件
-
EPOLLIN —— 读
-
EPOLLOUT —— 写
-
EPOLLERR —— 异常
-
struct epoll_event { /* 该结构体主要存放和fd有关的信息 */uint32_t events; epoll_data_t data; };typedef union epoll_data {void *ptr;int fd;uint32_t u32;uint64_t u64; } epoll_data_t;-
epoll_data_t是一个联合体union,四个成员共用同一块内存,也就是说四个成员我们只能用一个,一般情况下我们用fd,这个fd实际上就是epoll_ctl()函数的第三个参数fd。
-
如果我们想在epoll树上挂载更多信息,而不仅仅是fd文件描述符的话,我们可以把更多信息封装在结构体中,并把该结构体传给epoll_data_t结构体的ptr指针,这样就可以在epoll树上挂载和fd有关的更多信息。
struct sockInfo {int fd;struct sockaddr_in addr; };比如说,要获取发生变化的fd对应的client的IP和port,就可以利用指针ptr,这样的话联合epoll_data_t中的fd就不能用了,我们把文件描述符传给sockInfo的fd即可完成fd信息的挂载。
-
-
-
int epoll_wait(int epfd,struct epoll_event* events, /* 结构体数组 */int maxevents,int timeout);
-
函数功能:等待IO事件发生(可以设置阻塞),epoll_wait()函数相当于前面讲的select()或poll()函数,表示委托内核去进行检测。epoll_event通过返回值和传出参数events来实现把哪几个fd发生变化告诉server进程的目的。首先,每当有fd变化,就把这个fd对应的树节点拷贝到events数组中,最后,有几个fd变化,就返回几。这样只要根据返回值和参数events就可以遍历出所有变化的fd以及相关信息。
-
函数参数:
-
epfd:要检测的句柄
-
events:用于回传待处理事件的数组。它是一个传出参数,需要提前分配内存,哪个fd发生变化了,就把哪个fd的树节点(struct epoll_event)拷贝一份放到这个数组中。这样epoll就能返回是哪个fd发生了变化。
-
maxevents:告诉内核events的大小,因为内核要把发生变化的fd对应的树节点拷贝到数组中,所以要知道数组大小。
-
timeout:为超时时间
-
- -1:永久阻塞
- 0:立即返回
- >0
-
-
函数返回值:有多少个fd发生了变化就返回几(变化的fd信息存在events数组中)。
(2)epoll树

(3)epoll模型
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <sys/epoll.h>int main(int argc, const char* argv[])
{if(argc < 2){printf("eg: ./a.out port\n");exit(1);}struct sockaddr_in serv_addr;socklen_t serv_len = sizeof(serv_addr);int port = atoi(argv[1]); //字符串转整形值// 创建套接字int lfd = socket(AF_INET, SOCK_STREAM, 0);// 初始化服务器 sockaddr_in memset(&serv_addr, 0, serv_len);serv_addr.sin_family = AF_INET; // 地址族 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 监听本机所有的IPserv_addr.sin_port = htons(port); // 设置端口 // 绑定IP和端口bind(lfd, (struct sockaddr*)&serv_addr, serv_len);// 设置同时监听的最大个数listen(lfd, 36);printf("Start accept ......\n");struct sockaddr_in client_addr;socklen_t cli_len = sizeof(client_addr);// 创建epoll树根节点int epfd = epoll_create(2000);// 初始化epoll树struct epoll_event ev;ev.events = EPOLLIN;ev.data.fd = lfd;epoll_ctl(epfd, EPOLL_CTL_ADD, lfd, &ev);//存放发生变化的fd对应的树节点struct epoll_event all[2000];while(1){// 使用epoll通知内核fd 文件IO检测int ret = epoll_wait(epfd, all, sizeof(all)/sizeof(all[0]), -1);// 遍历all数组中的前ret个元素 //ret表示有几个变化的fd,变化的fd都存在all数组中for(int i=0; i<ret; ++i){int fd = all[i].data.fd;// 判断是否有新连接if(fd == lfd){// 接受连接请求 // accept不阻塞,因为已经有连接int cfd = accept(lfd, (struct sockaddr*)&client_addr, &cli_len);if(cfd == -1){perror("accept error");exit(1);}// 将新得到的cfd挂到树上struct epoll_event temp;temp.events = EPOLLIN; //检测cfd对应的读缓冲区,是否有数据传入temp.data.fd = cfd;epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &temp);// 打印客户端信息char ip[64] = {0};printf("New Client IP: %s, Port: %d\n",inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, ip, sizeof(ip)),ntohs(client_addr.sin_port));}else{// 处理已经连接的客户端发送过来的数据if(!all[i].events & EPOLLIN) //只处理读事件{continue;}/*假如说client发送过了100个数据,也就是serve的read缓冲区有100个数据,但是调用recv函数的时候只能读50个数据,而本次循环只调用了一次recv,那么只能下次循环再读剩余的50个数据,所以下次循环检测的时候,epoll_wait还是会返回,因为缓冲区还是剩余数据。这就是水平触发模式。这样的话虽然client只发了1次,但是epoll_wait会通知两次server去读数据。*/// 读数据char buf[1024] = {0};int len = recv(fd, buf, sizeof(buf), 0);if(len == -1){perror("recv error");exit(1);}else if(len == 0){printf("client disconnected ....\n");//close(fd);// fd从epoll树上删除ret = epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);// 挂树的时候需要ev,把ev挂在树上删除写NULL就行了if(ret == -1){perror("epoll_ctl del error");exit(1);}close(fd);}else{printf(" recv buf: %s\n", buf);write(fd, buf, len);}}}}close(lfd);return 0;
}
epoll维护的红黑树是存在一个共享内存中,内核和用户都可以通过操作这个共享内存来操作树,不需要内核态和用户态的切换,也不需要两种状态之间的数据拷贝,所以效率更高。
(4)epoll的三种工作模式
-
水平触发模式 - (根据读来解释)
-
- 只要fd对应的缓冲区有数据,epoll_wait就会返回
- 返回的次数与发送数据的次数没有关系
- epoll默认的工作模式
-
边沿触发模式 - ET
-
-
fd - 默认阻塞属性
-
客户端给server发数据:
-
-
发一次数据server 的 epoll_wait就返回一次
-
不在乎数据是否读完
-
如果读不完,如何把数据全部读出来?
-
-
while(recv());
-
- 数据读完之后recv会阻塞
- 解决阻塞问题 —— 设置非阻塞fd
-
-
-

对于epoll_wait()来说,epoll_wait 调用次数越多, 系统的开销越大。
水平触发模式会多次返回,只要server的read缓冲区有数据,epoll_wait就返回,也就会通知server去读数据,那么在循环检测的时候,只要server的read缓冲区有数据,epoll_wait就会多次调用,多次返回,并通知server去读数据;假如说client发送过了100个数据,也就是serve的read缓冲区有100个数据,但是调用recv函数的时候只能读50个数据,而本次循环只调用了一次recv,那么只能下次循环再读剩余的50个数据,所以下次循环检测的时候,epoll_wait还是会返回,因为缓冲区还是剩余数据。这就是水平触发模式。这样的话虽然client只发了1次,但是epoll_wait会通知两次server去读数据。 —— (printf函数是标准C库函数,C库函数都有一个默认缓冲区,printf的大小是8K。printf函数是行缓冲,使用printf函数的时候,如果不加 \n 会默认等到写满的时候才打印内容,加 \n 会强制把缓冲区的内容打印出来。另外 \0 表示结束,不加 \0 就会一直输出直到遇到 \0,用write(STDOUT_FILENO)替代printf函数就可以解决这些问题。)
边沿触发模式,client发一次数据epoll_wait只返回一次,也就只读一次,这样的话server的read缓冲区可能会有很多数据堆积,server读数据的时候可能读到的是上一次剩余的数据,并且只有client发的时候,epoll_wait才会通知server去读数据,边沿触发模式尽可能减少了epoll_wait的调用次数,缺点是数据有可能读不完导致堆积;
- 边沿非阻塞触发
-
-
效率最高
-
如何设置非阻塞
-
-
open()
-
- 设置flags
- 必须 O_WDRW | O_NONBLOCK
- 终端文件: /dev/tty
-
fcntl
-
- int flag = fcntl(fd, F_GETFL);
- flag |= O_NONBLOCK;
- fcntl(fd, F_SETFL, flag);
-
-
如何将缓冲区的全部数据都读出?
while(recv() > 0)
{
printf();
}
-
当缓冲区数据读完之后, 返回值是否为0?
-
- 阻塞状态
- 数据读完之后,recv阻塞
- 阻塞状态
-
- 非阻塞状态
- 强行读了一个没有数据的缓冲区(fd),数据已经被读完了,因为是非阻塞,所以在while循环中recv还要继续读,导致返回-1
- 判断 errno == EAGAIN
- 非阻塞状态
-
示例
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <errno.h>int main(int argc, const char* argv[])
{if(argc < 2){printf("eg: ./a.out port\n");exit(1);}struct sockaddr_in serv_addr;socklen_t serv_len = sizeof(serv_addr);int port = atoi(argv[1]);// 创建套接字int lfd = socket(AF_INET, SOCK_STREAM, 0);// 初始化服务器 sockaddr_in memset(&serv_addr, 0, serv_len);serv_addr.sin_family = AF_INET; // 地址族 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 监听本机所有的IPserv_addr.sin_port = htons(port); // 设置端口 // 绑定IP和端口bind(lfd, (struct sockaddr*)&serv_addr, serv_len);// 设置同时监听的最大个数listen(lfd, 36);printf("Start accept ......\n");struct sockaddr_in client_addr;socklen_t cli_len = sizeof(client_addr);// 创建epoll树根节点int epfd = epoll_create(2000);// 初始化epoll树struct epoll_event ev;// 设置边沿触发ev.events = EPOLLIN; //监听的文件描述符没必要边沿触发,主要是通信的cfdev.data.fd = lfd;epoll_ctl(epfd, EPOLL_CTL_ADD, lfd, &ev);struct epoll_event all[2000];while(1){// 使用epoll通知内核fd 文件IO检测int ret = epoll_wait(epfd, all, sizeof(all)/sizeof(all[0]), -1);printf("================== epoll_wait =============\n");// 遍历all数组中的前ret个元素for(int i=0; i<ret; ++i){int fd = all[i].data.fd;// 判断是否有新连接if(fd == lfd){// 接受连接请求int cfd = accept(lfd, (struct sockaddr*)&client_addr, &cli_len);if(cfd == -1){perror("accept error");exit(1);}// 设置文件cfd为非阻塞模式int flag = fcntl(cfd, F_GETFL);flag |= O_NONBLOCK;fcntl(cfd, F_SETFL, flag);// 将新得到的cfd挂到树上struct epoll_event temp;// 设置边沿触发temp.events = EPOLLIN | EPOLLET;temp.data.fd = cfd;epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &temp);// 打印客户端信息char ip[64] = {0};printf("New Client IP: %s, Port: %d\n",inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, ip, sizeof(ip)),ntohs(client_addr.sin_port));}else{// 处理已经连接的客户端发送过来的数据if(!all[i].events & EPOLLIN) {continue;}// 读数据char buf[5] = {0};int len;// 循环读数据while( (len = recv(fd, buf, sizeof(buf), 0)) > 0 ){// 数据打印到终端//不要用printf,因为printf如果找不到 \0 \n 字符会出现乱码,打印不出来等问题write(STDOUT_FILENO, buf, len);// 发送给客户端send(fd, buf, len, 0);}if(len == 0){printf("客户端断开了连接\n");ret = epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);if(ret == -1){perror("epoll_ctl - del error");exit(1);}close(fd);}else if(len == -1){//数据已经被读完了,因为是非阻塞,所以在while循环中recv还要继续读,导致返回-1if(errno == EAGAIN){printf("缓冲区数据已经读完\n");}else{//这才是真正的recv错误printf("recv error----\n");exit(1);}}
#if 0if(len == -1){perror("recv error");exit(1);}else if(len == 0){printf("client disconnected ....\n");// fd从epoll树上删除ret = epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);if(ret == -1){perror("epoll_ctl - del error");exit(1);}close(fd);}else{// printf(" recv buf: %s\n", buf);write(STDOUT_FILENO, buf, len);write(fd, buf, len);}
#endif}}}close(lfd);return 0;
}
(5)文件描述符1024限制
对于select来说,无法突破文件描述符1024上限,因为select是通过数组实现的。poll和epoll可以突破1024限制,poll是内部链表实现,而epoll是红黑树实现。
查看受计算机硬件限制的文件描述符上限可以通过下面命令
cat /proc/sys/fs/file-max
同样,我们也可以通过修改配置文件来修改这个上限,但是,我们在程序中设置的时候不能超过硬件限制的上限
vim /etc/security/limits.conf
-
soft nofile 8000 —— 也可以通过命令ulimit -n 2000来修改为2000
-
hard nofile 8000 —— 硬件资源限制
修改后重启系统即可起效。

![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6uPTgbmD-1682218134943)(Typora_picture_reference/1662196294315.png)]](https://img-blog.csdnimg.cn/2ed94d09fc2b4faead902a2be9ef0008.png)
图书推荐 -《构建高性能嵌入式系统》

购买链接:点击购买-链接1
点击购买-链接2
内容简介:
《构建高性能嵌入式系统》本书详细阐述了与构建高性能嵌入式系统相关的基本解决方案,主要包括构建高性能嵌入式系统、传感器、实时操作、FPGA项目、KiCad设计电路、构建高性能数字电路、固件开发、测试和调试嵌入式系统等内容。此外,本书还提供了相应的示例、代码,以帮助读者进一步理解相关方案的实现过程。

前 言
用于家庭、汽车和个人的现代数字设备包含越来越复杂的计算能力。这些嵌入式系统以每秒数千兆位的速率生成、接收和处理数字数据流。本书将教你如何使用现场可编程门阵列(Field Programmable Gate Array,FPGA)和高速数字电路设计技术来设计创建你自己的尖端数字设备。
本书读者
本书适用于软件开发人员、硬件工程师、物联网(IoT)开发人员以及其他任何寻求了解开发高性能嵌入式系统过程的人员。潜在受众包括有兴趣了解FPGA开发基础知识以及 C和C 固件开发所有方面的任何人。读者应当对C/C 语言、数字电路和焊接电子元件等有基本了解。
内容介绍
本书分为3篇,共10章,具体介绍如下。
第1篇:高性能嵌入式系统的基础知识,包括第1~3章。
第1章“高性能嵌入式系统”,详细阐释了嵌入式系统架构的元素,并讨论了在各种嵌入式应用中通用的一些关键系统特性。嵌入式系统通常包括至少一个微控制器或微处理器、传感器、执行器、电源,在许多情况下,还会有一个或多个网络接口。本章还深入探讨了嵌入式系统和物联网之间的关系。
第2章“感知世界”,详细介绍了在各种嵌入式应用中使用的传感器的原理和实现。无源传感器可测量周围环境的属性,如温度、压力、湿度、光强度和大气成分等。有源传感器则可以使用雷达和激光雷达等能量发射技术来探测物体并测量其位置和速度。此外,本章还介绍了与传感器通信的接口。
第3章“实时操作”,探讨了嵌入式系统对从传感器和其他来源测量的输入生成实时响应的需求,介绍了实时操作系统(RTOS)的概念及其关键特性,以及在实时应用程序中实现多任务处理时常见的一些挑战。此外,本章还介绍了一些流行的开源和商业RTOS实现的重要特征。
第2篇:设计和构建高性能嵌入式系统,包括第4~7章。
第4章“开发你的个FPGA项目”,首先讨论了实时嵌入式系统中 FPGA 设备的有效使用,然后阐释了标准FPGA中包含的功能元素。本章介绍了一系列FPGA设计语言,包括硬件描述语言(hardware description language,HDL)、原理图方法和流行的软件编程语言(包括C和C )。本章介绍了FPGA开发过程,并提供了一个FPGA开发周期的完整示例。
第5章“使用FPGA实现系统”,深入探讨了使用FPGA设计和实现嵌入式设备的过程。本章首先介绍了FPGA编译软件工具和编译过程,使用工具可将编程语言中的逻辑设计描述转换为可执行的FPGA配置。本章还讨论了适合FPGA实现的算法类型,后还开发了一个基于FPGA的高速数字示波器基础项目。
第6章“使用KiCad设计电路”,介绍了优秀的开源KiCad电子设计和自动化套件。在KiCad中工作可以使用原理图设计电路并开发相应的印刷电路板布局。你将了解如何以非常合理的成本将电路板设计转变为原型产品。
第7章“构建高性能数字电路”,详细阐释了使用表面贴装和通孔电子元件组装高性能数字电路原型所涉及的过程和技术。本章介绍的电路板组装工具包括焊台、放大镜或显微镜以及用于处理微小零件的镊子等。此外,本章还介绍了回流焊接工艺,并描述了一些用于实现小规模回流能力的低成本选项。
第3篇:实现和测试实时固件,包括第8~10章。
第8章“首次给电路板通电”,介绍了如何为电路板通电做准备。本章将引导你完成首次向电路板供电并检查基本电路级功能的过程。发现任何问题时,可以按本章建议的方法调整电路。在测试通过之后,还可以添加FPGA逻辑,并测试示波器电路板的数字接口。
第9章“固件开发过程”,演示了如何在电路板正常运行后充实FPGA算法的其余关键部分,包括与模数转换器(analog to digital converter,ADC)的通信,以及MicroBlaze处理器固件的开发。在开发固件时,重要的是尽可能对代码进行静态分析,这样可以避免许多难以调试的错误。实现版本控制系统以跟踪项目生命周期中代码的演变也很重要。本章讨论了开发一个全面的、至少部分自动化的测试套件对于在进行更改时保持代码质量的重要性。此外,本章还着重介绍了编码风格。
第10章“测试和调试嵌入式系统”,讨论了嵌入式系统的全面测试问题。系统级测试必须针对整个系统预期范围的环境条件和用户输入(包括无效输入),以确保系统在所有条件下都能正常运行。此外,本章还讨论了有效调试技术,总结了高性能嵌入式系统开发的实践。
充分利用本书
本书充分利用了强大的免费商业和开源软件工具套件来开发FPGA算法和设计复杂的印刷电路板。要跟随本书示例项目学习,你需要一个特定的FPGA开发板Digilent Arty A7-100。要构建数字电路以实现你的设计,你还需要一套用于焊接和拆焊表面贴装元件的工具。此外,你可能还需要一些工具来协助处理精细元件,如精密镊子、放大镜或显微镜等。






相关文章:
【文末送书】计算机网络 | IO多路转接技术 | poll/epoll详解
欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起学习和分享Linux、C、C、Python、Matlab,机器人运动控制、多机器人协作,智能优化算法,滤波估计、多传感器信息融合,机器学习,人工智能等相关领域的知识和…...
【Linux】 uptime命令使用
uptime 正常运行时间提供以下信息的单行显示。当前时间、系统运行的时间、当前登录的用户数量以及过去1、5和15分钟的系统平均负载。 语法 uptimeuptime命令 -Linux手册页 作者 由Larry Greenfield编写和迈克尔K约翰逊编写。 命令选项及作用 执行令 man uptime 执行命令结…...
数学建模-图与网络模型解题方法和代码实现
本文针对以下几个方面问题进行整理: 最短路问题 两个指定顶点之间的最短路径任意顶点之间的最短路径 2.最小生成树问题 求最小生成树 3.网络最大流问题 源点与汇点之间的最大流基于最大流的最小费用求解 4.旅行商问题 基于哈密顿(Hamilton)圈求解旅行商线性…...
宏集新闻 | 虹科传感器事业部正式更名为宏集科技
致一直支持“虹科传感器”的朋友们: 为进一步整合资源,给您带来更全面、更优质的服务,我们非常荣幸地宣布,虹科传感器事业部已正式更名为宏集科技。这一重要的改变代表了虹科持续发展进程中的新里程碑,也体现了我们在传…...
DataFunSummit:2023年数据基础架构峰会-核心PPT资料下载
一、峰会简介 正如From、Join、排序等是SQL的基本算子,存储与计算是也是数据架构中数据生产与消费的基本算子,对于数据架构之下的技术栈层级,我们可将其定义为数据基础架构。 数据存储技术在适应大数据时代的规模需求基础之上,持…...
解析大型语言模型的训练、微调和推理的运行时性能
背景 这篇论文是截至目前为数不多的介绍大模型训练配套环境比对的论文,对于想要入门大模型训练同学是个不错的入门资料。比较了不同尺寸模型(比较常用的7、13、70b),在不同型号gpu、训练框架、推理框架数据。结合自己实际工作需要…...
MAX/MSP SDK学习06:内存管理
提供两种内存分配方式:①简单指针,②句柄(二级指针);官方文档建议使用前者。 // 简单指针 char *ptr; ptr sysmem_newptr(2000); post("I have a pointer %lx and it is %ld bytes in size",ptr, sysmem_p…...
python网络通信之基础知识填坑
文章目录 版权声明网络通信要素IP地址ifconfig和ping命令ifconfig (Interface Configuration)ping 端口和端口号的介绍端口号的分类socket介绍TCPTCP简介TCP的特点 UDPUDP简介UDP特点 版权声明 本博客的内容基于我个人学习黑马程序员课程的学习笔记整理而成。我特此声明&#…...
【腾讯云云上实验室-向量数据库】腾讯云开创新时代,发布全新向量数据库Tencent Cloud VectorDB
前言 随着人工智能、数据挖掘等技术的飞速发展,海量数据的存储和分析越来越成为重要的研究方向。在海量数据中找到具有相似性或相关性的数据对于实现精准推荐、搜索等应用至关重要。传统关系型数据库存在一些缺陷,例如存储效率低、查询耗时长等问题&…...
【图像分类】【深度学习】【Pytorch版本】GoogLeNet(InceptionV4)模型算法详解
【图像分类】【深度学习】【Pytorch版本】GoogLeNet(InceptionV4)模型算法详解 文章目录 【图像分类】【深度学习】【Pytorch版本】GoogLeNet(InceptionV4)模型算法详解前言GoogLeNet(InceptionV4)讲解Stem结构Inception-A结构Inception- B结构Inception-C结构Redution-A结构Re…...
opencv dots_image_kernel
1,opencv dots_image_kernel // halcon dots_image kernel估算(d5) cv::Mat getDotKernel(int d 5){// 保证d为正的奇数d | 0x01;cv::Mat kernel cv::Mat::zeros(d 2, d 2, CV_8UC1);int cx kernel.cols / 2;int cy kernel.rows / 2;int cnt255 0, cnt128 …...
使用pytorch利用神经网络原理进行图片的训练(持续学习中....)
1.做这件事的目的 语言只是工具,使用python训练图片数据,最终会得到.pth的训练文件,java有使用这个文件进行图片识别的工具,顺便整合,我觉得Neo4J正确率太低了,草莓都能识别成为苹果,而且速度慢,不能持续识别视频帧 2.什么是神经网络?(其实就是数学的排列组合最终得到统计结果…...
2023年中国合成云母行业现状及市场格局分析[图]
合成云母是一种通过化工原料经高温熔融冷却析晶而制得的单斜晶系矿物,属于典型的层状硅酸盐,许多性能都优于天然云母,如合成云母的耐温高达1200℃以上,而天然白云母在550℃下就会开始分解,金云母则在800℃开始分解。除…...
Vue3+Vite实现工程化,插值表达式和v-text以及v-html
1、插值表达式 插值表达式最基本的数据绑定形式是文本插值,它使用的是"Mustache"语法,即 双大括号{{}} 插值表达式是将数据 渲染 到元素的指定位置的手段之一插值表达式 不绝对依赖标签,其位置相对自由插值表达式中支持javascript的…...
艾泊宇产品战略:灵感于鬼屋,掌握打造卓越用户体验的关键要素
在当今的商业环境中,用户体验已经成为产品成功的关键因素。 无论是线上产品还是实体产品,用户体验都是决定用户是否愿意使用和推荐该产品的关键因素。 那么,艾泊宇产品战略理论告诉大家,如何做好用户体验? 我们可以…...
深度学习环境配置(Anaconda+pytorch+pycharm+cuda)
NVIDIA驱动安装 首先查看电脑的显卡版本,步骤为:此电脑右击-->管理-->设备管理器-->显示适配器。就可以看到电脑显卡的版本了。 然后按照电脑信息,到地址 去安装相应的驱动,Notebooks是笔记本的意思,然后下…...
不是说人工智能是风口吗,那为什么工作还那么难找?
最近确实有很多媒体、机构渲染人工智能可以拿高薪,这在行业内也是事实,但前提是你有足够的竞争力,真的懂人工智能。 首先,人工智能岗位技能要求高,人工智能是一个涵盖了多个学科领域的综合性学科,包括数学、…...
new Vue() 发生了什么
前言: 在Vue.js中,当你创建一个新的Vue实例时,通过 new Vue() 发生了一系列重要的操作,包括Vue实例的初始化、数据绑定、模板编译等。这个过程是Vue应用的核心,本文将深入探讨new Vue()发生了什么以及其原理,提供示例…...
【算法】二叉树的存储与遍历模板
二叉树的存储与遍历 const int N 1e6 10;// 二叉树的存储,l数组为左节点,r数组为右结点 int l[N], r[N]; // 存储节点的数据 char w[N]; // 节点的下标指针 int idx 0;// 先序创建 int pre_create(int n) {cin >> w[n];if (w[n] #) return -1;l[n] pre_create(idx)…...
【Go学习之 go mod】gomod小白入门,在github上发布自己的项目(项目初始化、项目发布、项目版本升级等)
参考 Go语言基础之包 | 李文周的博客Go mod的使用、发布、升级 | weiGo Module如何发布v2及以上版本1.2.7. go mod命令 — 新溪-gordon V1.7.9 文档golang go 包管理工具 go mod的详细介绍-腾讯云开发者社区-腾讯云Go Mod 常见错误的原因 | walker的博客 项目案例 oceanweav…...
网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...
centos 7 部署awstats 网站访问检测
一、基础环境准备(两种安装方式都要做) bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats࿰…...
如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...
sqlserver 根据指定字符 解析拼接字符串
DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...
Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...
Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...

