I/O多路复用三种实现
一.select 实现
(1)select流程
基本流程是:
1. 先构造一张有关文件描述符的表; fd_set readfds
2. 清空表 FD_ZERO()
3. 将你关心的文件描述符加入到这个表中; FD_SET()
4. 调用select函数。 selset()
5. 判断是哪一个或哪些文件描述符产生了事件(IO操作); FD_ISSET()
6. 做对应的逻辑处理;
(2)selset函数
头文件: #include<sys/select.h> #include<sys/time.h>
#include<sys/types.h> #include<unistd.h>
声明: int select(int nfds, fd_set *readfds, fd_set *writefds,\
fd_set *exceptfds, struct timeval *timeout);
功能:监测是哪些文件描述符产生事件,阻塞等待产生.
参数:nfds: 监测的最大文件描述个数(文件描述符从0开始,这里是个数,记得+1)
readfds: 读事件集合; // 键盘鼠标的输入,客户端连接都是读事件
writefds: 写事件集合; //NULL表示不关心
exceptfds:异常事件集合; //NULL 表示不关心
timeout: 设为NULL,等待直到某个文件描述符发生变化;
设为大于0的值,有描述符变化或超时时间到才返回。
超时时间检测:如果规定时间内未完成函数功能,返回一个超时的信息,我们可以根据该信息设定相应需求;
返回值: <0 出错 >0 表示有事件产生;
如果设置了超时检测时间:&tv
<0 出错 >0 表示有事件产生; ==0 表示超时时间已到;
结构体如下:
struct timeval {
long tv_sec; 以秒为单位,指定等待时间
long tv_usec; 以毫秒为单位,指定等待时间
};
void FD_CLR(int fd, fd_set *set); //将set集合中的fd清除掉
int FD_ISSET(int fd, fd_set *set); //判断fd是否在set集合中产生了事件
void FD_SET(int fd, fd_set *set); //将fd加入到集合中
void FD_ZERO(fd_set *set); //清空集合
(3)Select特点:
Select特点:
1. 一个进程最多只能监听1024个文件描述符 (32位) [64位为 2048]
2. select被唤醒之后要重新轮询(0-1023)一遍驱动,效率低(消耗CPU资源)
3. select每次会清空未响应的文件描述符,每次都需要拷贝用户空间的表到内核空间,效率低,开销较大
(0~3G是用户态,3G~4G是内核态,两个状态来回切换 拷贝是非常耗时,耗资源的)
(4)select机制:
1. 头文件检测1024个文件描述符 0-1023
2. 在select中0~2存储标准输入、标准输出、标准出错
3. 监测的最大文件描述个数为fd+1(如果fd = 3,则最大为 4) : //因为从0开始的
4. select只对置1的文件描述符感兴趣 ,假如事件产生,select检测时 , 产生的文件描述符会保持1,未产生事件的会置0;
5. select每次轮询都会清空表(置零的清空) //需要在select前备份临时表
练习1:
如何通过select实现 响应鼠标事件同时响应键盘事件?
代码:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>int main(int argc, char const *argv[])
{int fd = open("/dev/input/mouse0", O_RDONLY);if (fd < 0){perror("open is err:");return -1;}//1.创建表fd_set readfds;//2/清空表FD_ZERO(&readfds);//3.设置表FD_SET(0, &readfds);FD_SET(fd, &readfds);fd_set readfdcp = readfds;int maxfd = fd;char buf[128] = {0};while (1){//4.检测是否有相应select(maxfd + 1, &readfds, NULL, NULL, NULL);//5.检测哪一个文件描述符if (FD_ISSET(0, &readfds)){fgets(buf, sizeof(buf), stdin);if (buf[strlen(buf) - 1] == '\n')buf[strlen(buf) - 1] = '\0';printf("key: %s\n", buf);}if (FD_ISSET(fd, &readfds)){int ret = read(fd, buf, sizeof(buf));buf[ret] = '\0';printf("mouse: %s\n", buf);}readfds = readfdcp;}return 0;
}
练习2:
select是文件描述符和下标一一对应,0只能对应0号文件描述符。因此只有最大的文件描述符关闭时,才--len。注意增加删除时是针对实际表,不是临时表。
使用select实现server的全双工
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <signal.h>
#include <sys/select.h>int acceptfp;
int main(int argc, char const *argv[])
{char buf[128] = {0};//1.创建套接字,返回建立链接的文件描述符int sockfp = socket(AF_INET, SOCK_STREAM, 0);if (sockfp == -1){perror("socket is err");exit(0);}printf("%d\n", sockfp);//2.绑定ip和端口号struct sockaddr_in saddr, caddr;saddr.sin_family = AF_INET;saddr.sin_port = htons(atoi(argv[1]));saddr.sin_addr.s_addr = inet_addr("0.0.0.0");socklen_t len = sizeof(struct sockaddr_in);if (bind(sockfp, (struct sockaddr *)&saddr, sizeof(saddr)) < 0){perror("bind is err");exit(0);}//3.listen监听if (listen(sockfp, 5)){perror("liste err");exit(0);}printf("listen ok\n");//1.创建表fd_set readfds;//2/清空表FD_ZERO(&readfds);//3.设置表FD_SET(0, &readfds);FD_SET(sockfp, &readfds);fd_set readfdcp = readfds;int maxfd = sockfp;struct timeval st;while (1){readfds = readfdcp;//4.检测是否有响应st.tv_sec = 5;st.tv_usec = 0;int ret = select(maxfd + 1, &readfds, NULL, NULL, &st);if (ret < 0){perror("select err");return -1;}else if (ret == 0){printf("无响应\n");}//0响应,证明服务器要发送消息if (FD_ISSET(0, &readfds)){fgets(buf, sizeof(buf), stdin);if (buf[strlen(buf) - 1] == '\n')buf[strlen(buf) - 1] = '\0';for (int i = 4; i <= maxfd; ++i){send(i, buf, sizeof(buf), 0);}}//sockfp,监听套接字响应证明,有客户端要链接if (FD_ISSET(sockfp, &readfds)){acceptfp = accept(sockfp, (struct sockaddr *)&caddr, &len);if (acceptfp < 0){perror("acceptfp");exit(0);}printf("port:%d ip: %s\n", ntohs(caddr.sin_port), inet_ntoa(caddr.sin_addr));FD_SET(acceptfp, &readfdcp);if (acceptfp > maxfd)maxfd = acceptfp;}//检测客户端,检查是哪一个客户端发送的消息for (int i = 4; i <= maxfd; ++i){if (FD_ISSET(i, &readfds)){int recvbyte = recv(i, buf, sizeof(buf), 0);if (recvbyte < 0){perror("recv err");return -1;}else if (recvbyte == 0){printf("%d client is exit\n", i);close(i);FD_CLR(i, &readfdcp);if (i == maxfd)--maxfd;}else{printf("%d : %s\n", i, buf);}}}}return 0;
}
练习3:
使用select实现client的全双工
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>int main(int argc, const char *argv[])
{int sockfd = socket(AF_INET,SOCK_STREAM,0);if(sockfd < 0){perror("socker is err:");return -1;}struct sockaddr_in saddr;saddr.sin_family = AF_INET;saddr.sin_port = htons(atoi(argv[1]));saddr.sin_addr.s_addr = inet_addr(argv[2]);if(connect(sockfd,(struct sockaddr *)&saddr,sizeof(saddr)) < 0){perror("connect is err:");return -1;}//1.创建表fd_set readfds,tempfds;//2.清空表FD_ZERO(&readfds);FD_ZERO(&tempfds);//3.添加文件描述符FD_SET(0,&readfds);FD_SET(sockfd,&readfds);int maxfd = sockfd;int ret;char buf[128];while(1){tempfds = readfds;//4.调select检测ret = select(maxfd+1,&tempfds,NULL,NULL,NULL);if(ret < 0){perror("select is err:");return -1;}if(FD_ISSET(0,&tempfds)){fgets(buf,sizeof(buf),stdin);if(buf[strlen(buf)-1] == '\n')buf[strlen(buf)-1] = '\0';send(sockfd,buf,sizeof(buf),0);}if(FD_ISSET(sockfd,&tempfds)){int recvbyte = recv(sockfd,buf,sizeof(buf),0);if(recvbyte < 0){perror("recv is err:");return -1;}printf("%s\n",buf);}}close(sockfd);return 0;
}
(5)select的超时时间检测:
超时检测的必要性:
1. 避免进程在没有数据时无限制的阻塞;
2. 规定时间未完成语句应有的功能,则会执行相关功能;
结构体如下:
struct timeval {
long tv_sec; 以秒为单位,指定等待时间
long tv_usec; 以毫秒为单位,指定等待时间
};
二.poll实现
(1)poll流程
使用: 1.先创建结构体数组 struct pollfd fds[100];
2.添加结构体成员的文件描述符以及触发方式 fds[0].fd = ?;fds[0].events = POLLIN
3.保存数组内最后一个有效元素的下标
4. 调用函数poll ret = poll(fds,nfds+1,-1);
5.判断结构体内文件描述符是否触发事件 fds[i].revents == POLLIN
6.根据不同的文件描述符触发不同事件
(2)poll函数
声明:int poll(struct pollfd *fds, nfds_t nfds, int timeout);
头文件: #include<poll.h>
功能: 监视并等待多个文件描述符的属性变化
参数:
1.struct pollfd *fds: 关心的文件描述符数组,大小自己定义
若想检测的文件描述符较多,则建 立结构体数组struct pollfd fds[N];
struct pollfd
{
int fd; //文件描述符
short events; //等待的事件触发条件----POLLIN读时间触发(大多数)
short revents; //实际发生的事件(未产生事件: 0 ))
}
2. nfds: 最大文件描述符个数
3. timeout: 超时检测 (毫秒级):1000 == 1s
如果-1,阻塞 如果0,不阻塞
返回值: <0 出错 >0 表示有事件产生;
如果设置了超时检测时间:&tv
<0 出错 >0 表示有事件产生; ==0 表示超时时间已到;
(3)poll特点
1. 优化文件描述符个数的限制;
(根据poll函数第一个函数的参数来定,如果监听的事件为1个,则结构体数组容量为1,如果想监听100个,那么这个结构体数组的容量就为100,多少文件描述符由程序员自己来决定)
2. poll被唤醒之后需要重新轮询一遍驱动,效率比较低(消耗CPU)
3. poll不需重新构造文件描述符表(也不需清空表),只需要从用户空间向内核空间拷贝一次数据(效率相对比较高)
练习:
使用poll实现server的全双工
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <signal.h>
#include <sys/select.h>
#include <poll.h>int acceptfp;
int main(int argc, char const *argv[])
{char buf[128] = {0};//1.创建套接字,返回建立链接的文件描述符int sockfp = socket(AF_INET, SOCK_STREAM, 0);if (sockfp == -1){perror("socket is err");exit(0);}printf("%d\n", sockfp);//2.绑定ip和端口号struct sockaddr_in saddr, caddr;saddr.sin_family = AF_INET;saddr.sin_port = htons(atoi(argv[1]));saddr.sin_addr.s_addr = inet_addr("0.0.0.0");socklen_t len = sizeof(struct sockaddr_in);if (bind(sockfp, (struct sockaddr *)&saddr, sizeof(saddr)) < 0){perror("bind is err");exit(0);}//3.listen监听if (listen(sockfp, 5)){perror("liste err");exit(0);}printf("listen ok\n");//1.创建结构体数组struct pollfd fds[100];//2.添加文件描述符和触发方式fds[0].fd = 0;fds[0].events = POLLIN;fds[1].fd = sockfp;fds[1].events = POLLIN;int nfds = 1;int ret;while (1){//3.poll轮循检测ret = poll(fds, nfds + 1, 2000);if (ret < 0){perror("poll is err");return -1;}else if (ret == 0){printf("qeqweqe\n");continue;}//4. 判断哪一个文件描述符产生响应,并发布任务for (int i = 0; i <= nfds; ++i){if (fds[i].revents == POLLIN){if (fds[i].fd == 0){fgets(buf, sizeof(buf), stdin);if (buf[strlen(buf) - 1] == '\n')buf[strlen(buf) - 1] = '\0';//printf("发送信息:\n");for (int j = 2; j <= nfds; ++j){send(fds[j].fd, buf, sizeof(buf), 0);}}else if (fds[i].fd == sockfp){acceptfp = accept(sockfp, (struct sockaddr *)&caddr, &len);if (acceptfp < 0){perror("acceptfp");exit(0);}printf("port:%d ip: %s\n", ntohs(caddr.sin_port), inet_ntoa(caddr.sin_addr));fds[++nfds].fd = acceptfp;fds[nfds].events = POLLIN;}else{int recvbyte = recv(fds[i].fd, buf, sizeof(buf), 0);if (recvbyte < 0){perror("recv err");return -1;}else if (recvbyte == 0){printf("%d client is exit\n", i);close(fds[i].fd);//覆盖fds[i] = fds[nfds];//--i,--nfds后,最后一个循环不到--nfds, --i;}else{printf("%d : %s\n", i, buf);}}}}}return 0;
}
(4)poll超时时间检测
timeout: 超时检测 (毫秒级):1000 == 1s
如果-1,阻塞 如果0,不阻塞
三.epoll实现
(1)epoll流程:
Epoll的使用:
1.创建红黑树 和 就绪链表 int epfd = epoll_create(1);
2.添加文件描述符和事件信息到树上
event.events = EPOLLIN|EPOLLET;
event.data.fd = 0;
epoll_ctl(epfd,EPOLL_CTL_ADD,0,&event
3.阻塞等待事件的产生,一旦产生事件,则进行处理
int ret = epoll_wait(epfd,events,32,-1);
4.根据链中准备处理的文件描述符 进行处理
(2)epoll函数族
epoll 要使用一组函数: epoll_create 创建红黑树 和 就序链表
epoll_ctl 添加文件描述符和事件到树上 / 从树上删除
epoll_wait 等待事件产生
epoll_create
创建红黑树以及链表
头文件:#include <sys/epoll.h>
声明:int epoll_create(int size);
功能:创建红黑树根节点(创建epoll实例) , 同时也会创建就绪链表
返回值:成功时返回一个实例(二叉树句柄),失败时返回-1。
epoll_ctl
控制epoll属性
声明: int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
功能:控制epoll属性,比如给红黑树添加节点
参数: 1. epfd: epoll_create函数的返回句柄。//一个标识符
2. op:表示动作类型,有三个宏:
EPOLL_CTL_ADD:注册新的fd到epfd中
EPOLL_CTL_MOD:修改已注册fd的监听事件
EPOLL_CTL_DEL:从epfd中删除一个fd
3. 要操作的文件描述符
4. 结构体信息:
typedef union epoll_data {
int fd; //要添加的文件描述符,只用这个
uint32_t u32; typedef unsigned int
uint64_t u64; typedef unsigned long int
} epoll_data_t;
struct epoll_event {
uint32_t events; 事件
epoll_data_t data; //共用体(看上面)
};
关于events事件:
EPOLLIN: 表示对应文件描述符可读
EPOLLOUT: 可写
EPOLLPRI:有紧急数据可读;
EPOLLERR:错误;
EPOLLHUP:被挂断;
EPOLLET:触发方式,边缘触发;(默认使用边缘触发)
ET模式:表示状态的变化;
NULL: 删除一个文件描述符使用,无事件
返回值:成功:0, 失败:-1
epoll_wait
等待事件产生
声明: int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
功能:等待事件产生
内核会查找红黑树中有事件响应的文件描述符, 并将这些文件描述符放入就绪链表
就绪链表中的内容, 执行epoll_wait会同时复制到第二个参数events
参数: epfd:句柄;
events:用来保存从就绪链表中响应事件的集合;(传出参数,定义结构体数组)
maxevents: 表示每次在链表中拿取响应事件的个数;
timeout:超时时间,毫秒,0立即返回 ,-1阻塞
返回值: 成功: 实际从链表中拿出的数目 失败时返回-1
(4)epoll特点
1.监听的最大的文件描述符没有个数限制(取决与你自己的系统 1GB - 10万个左右)
2.异步I/O,epoll当有事件产生被唤醒之后,文件描述符主动调用callback(回调函数)函数直接拿到唤醒的文件描述符,不需要轮询,效率高
3.epoll不需要重新构造文件描述符表,只需要从用户空间向内核空间拷贝一次数据即可.
(5)epoll机制
select,poll都属于 同步IO机制(轮询)
epoll属于异步IO机制(不轮询):
Epoll处理高并发,百万级
- 红黑树: 是特殊的二叉树(每个节点带有属性),Epoll怎样能监听很多个呢?首先创建树的根节点,每个节点都是一个fd以结构体的形式存储(节点里面包含了一些属性,callback函数)
- 就绪链表: 当某一个文件描述符产生事件后,会自动调用callback函数,通过回调callback函数来找到链表对应的事件(读时间还是写事件)。
练习:
epoll实现server
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <signal.h>
#include <sys/select.h>
#include <poll.h>
#include <sys/epoll.h>int acceptfp;
int main(int argc, char const *argv[])
{char buf[128] = {0};//1.创建套接字,返回建立链接的文件描述符int sockfp = socket(AF_INET, SOCK_STREAM, 0);if (sockfp == -1){perror("socket is err");exit(0);}printf("%d\n", sockfp);//2.绑定ip和端口号struct sockaddr_in saddr, caddr;saddr.sin_family = AF_INET;saddr.sin_port = htons(atoi(argv[1]));saddr.sin_addr.s_addr = inet_addr("0.0.0.0");socklen_t len = sizeof(struct sockaddr_in);if (bind(sockfp, (struct sockaddr *)&saddr, sizeof(saddr)) < 0){perror("bind is err");exit(0);}//3.listen监听if (listen(sockfp, 5)){perror("liste err");exit(0);}printf("listen ok\n");//1.创建红黑树以及链表//树的跟节点/树的句柄int epfd = epoll_create(1);//2.上树struct epoll_event event;struct epoll_event events[32] ;event.events = EPOLLET | EPOLLIN;event.data.fd = 0;epoll_ctl(epfd, EPOLL_CTL_ADD, 0, &event);event.data.fd = sockfp;epoll_ctl(epfd, EPOLL_CTL_ADD, sockfp, &event);while (1){//3.阻塞等待文件描述符产生事件int ret = epoll_wait(epfd, events, 32, -1);printf("asdsdfgdsf\n");if (ret < 0){perror("epoll err");return -1;}//4.根据文件描述符号,进行处理for (int i = 0; i < ret; ++i){if (events[i].data.fd == 0){fgets(buf, sizeof(buf), stdin);if (buf[strlen(buf) - 1] == '\n')buf[strlen(buf) - 1] = '\0';printf("发送信息:\n");//send(fds[j].fd, buf, sizeof(buf), 0);}else if (events[i].data.fd == sockfp){acceptfp = accept(sockfp, (struct sockaddr *)&caddr, &len);if (acceptfp < 0){perror("acceptfp");exit(0);}printf("port:%d ip: %s\n", ntohs(caddr.sin_port), inet_ntoa(caddr.sin_addr));//上树event.data.fd = acceptfp;epoll_ctl(epfd, EPOLL_CTL_ADD, acceptfp, &event);}else{int recvbyte = recv(events[i].data.fd, buf, sizeof(buf), 0);if (recvbyte < 0){perror("recv err");return -1;}else if (recvbyte == 0){printf("%d client is exit\n", events[i].data.fd);close(events[i].data.fd);//下树epoll_ctl(epfd, EPOLL_CTL_DEL, events[i].data.fd, NULL);}else{printf("%d : %s\n", events[i].data.fd, buf);}}}}return 0;
}
对比
相关文章:

I/O多路复用三种实现
一.select 实现 (1)select流程 基本流程是: 1. 先构造一张有关文件描述符的表; fd_set readfds 2. 清空表 FD_ZERO() 3. 将你关心的文件描述符加入到这…...

DataInputStream数据读取 Vs ByteBuffer数据读取的巨大性能差距
背景: 今天在查找一个序列化和反序列化相关的问题时,意外发现使用DataInputStream读取和ByteBuffer读取之间性能相差巨大,本文就来记录下这两者在读取整数类型时的性能差异,以便在平时使用的过程中引起注意 DataInputStream数据…...

org.apache.flink.table.api.TableException: Sink does not exists
FlinkSQL_1.12_用DDL实现Kafka到MySQL的数据传输_实现按照条件进行过滤写入MySQL_flink从kafka拉取数据并过滤数据写入mysql_旧城里的阳光的博客-CSDN博客 参考这篇文章,写了kafka到mysql的代码例子,因为自己改了表结构,运行下面代码&#x…...

【多线程】CAS 详解
CAS 详解 一. 什么是 CAS二. CAS 的应用1. 实现原子类2. 实现自旋锁 三. CAS 的 ABA 问题四. 相关面试题 一. 什么是 CAS CAS: 全称Compare and swap,字面意思:”比较并交换“一个 CAS 涉及到以下操作: 我们假设内存中的原数据 V,旧的预期值…...

卷积神经网络实现咖啡豆分类 - P7
🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 | 接辅导、项目定制🚀 文章来源:K同学的学习圈子 目录 环境步骤环境设置包引用全局设备对象 数据准备查看图像的信息制作数据集 模型设…...

C++之默认与自定义构造函数问题(二百一十七)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生…...

Docker从认识到实践再到底层原理(五)|Docker镜像
前言 那么这里博主先安利一些干货满满的专栏了! 首先是博主的高质量博客的汇总,这个专栏里面的博客,都是博主最最用心写的一部分,干货满满,希望对大家有帮助。 高质量博客汇总 然后就是博主最近最花时间的一个专栏…...

【Flowable】任务监听器(五)
前言 之前有需要使用到Flowable,鉴于网上的资料不是很多也不是很全也是捣鼓了半天,因此争取能在这里简单分享一下经验,帮助有需要的朋友,也非常欢迎大家指出不足的地方。 一、监听器 在Flowable中,我们可以使用监听…...

spring-kafka中ContainerProperties.AckMode详解
近期,我们线上遇到了一个性能问题,几乎快引起线上故障,后来仅仅是修改了一行代码,性能就提升了几十倍。一行代码几十倍,数据听起来很夸张,不过这是真实的数据,线上错误的配置的确有可能导致性能…...

【rpc】Dubbo和Zookeeper结合使用,它们的作用与联系(通俗易懂,一文理解)
目录 Dubbo是什么? 把系统模块变成分布式,有哪些好处,本来能在一台机子上运行,为什么还要远程调用 Zookeeper是什么? 它们进行配合使用时,之间的关系 服务注册 服务发现 动态地址管理 Dubbo是…...

ChatGPT的未来
随着人工智能的快速发展,ChatGPT作为一种自然语言生成模型,在各个领域都展现出了巨大的潜力。它不仅可以用于日常对话、创意助手和知识查询,还可以应用于教育、医疗、商业等各个领域,为人们带来更多便利和创新。 在教育领域&#…...

Pytorch模型转ONNX部署
开始以为会很困难,但是其实非常方便,下边分两步走:1. pytorch模型转onnx;2. 使用onnx进行inference 0. 准备工作 0.1 安装onnx 安装onnx和onnxruntime,onnx貌似是个环境。。倒是没有直接使用,onnxruntim…...

k8s优雅停服
在应用程序的整个生命周期中,正在运行的 pod 会由于多种原因而终止。在某些情况下,Kubernetes 会因用户输入(例如更新或删除 Deployment 时)而终止 pod。在其他情况下,Kubernetes 需要释放给定节点上的资源时会终止 po…...

面试题五:computed的使用
题记 大部分的工作中使用computed的频次很低的,所以今天拿出来一文对于computed进行详细的介绍,因为Vue的灵魂之一就是computed。 模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护…...

完美的分布式监控系统 Prometheus与优雅的开源可视化平台 Grafana
1、之间的关系 prometheus与grafana之间是相辅相成的关系。简而言之Grafana作为可视化的平台,平台的数据从Prometheus中取到来进行仪表盘的展示。而Prometheus这源源不断的给Grafana提供数据的支持。 Prometheus是一个开源的系统监控和报警系统,能够监…...

黑马JVM总结(九)
(1)StringTable_调优1 我们知道StringTable底层是一个哈希表,哈希表的性能是跟它的大小相关的,如果哈希表这个桶的个数比较多,元素相对分散,哈希碰撞的几率就会减少,查找的速度较快,…...

如何使用 RunwayML 进行创意 AI 创作
标题:如何使用 RunwayML 进行创意 AI 创作 介绍 RunwayML 是一个基于浏览器的人工智能创作工具,可让用户使用各种 AI 功能来生成图像、视频、音乐、文字和其他创意内容。RunwayML 的功能包括: * 图像生成:使用生成式对抗网络 (…...

【css】能被4整除 css :class,判断一个数能否被另外一个数整除,余数
判断一个数能否被另外一个数整除 一个数能被4整除的表达式可以表示为:num%40,其中,num为待判断的数,% 为取模运算符,为等于运算符。这个表达式的意思是,如果num除以4的余数为0,则返回true&…...

ChatGPT与日本首相交流核废水事件-精准Prompt...
了解更多请点击:ChatGPT与日本首相交流核废水事件-精准Prompt...https://mp.weixin.qq.com/s?__bizMzg2NDY3NjY5NA&mid2247490070&idx1&snebdc608acd419bb3e71ca46acee04890&chksmce64e42ff9136d39743d16059e2c9509cc799a7b15e8f4d4f71caa25968554…...

关于 firefox 不能访问 http 的解决
情景: 我在虚拟机 192.168.x.111 上配置了 DNS 服务器,在 kali 上设置 192.168.x.111 为 DNS 服务器后,使用 firefox 地址栏搜索域名 www.xxx.com ,访问在 192.168.x.111 搭建的网站,本来经 192.168.x.111 DNS 服务器解…...

68、Spring Data JPA 的 方法名关键字查询
★ 方法名关键字查询(全自动) (1)继承 CrudRepository 接口 的 DAO 组件可按特定规则来定义查询方法,只要这些查询方法的 方法名 遵守特定的规则,Spring Data 将会自动为这些方法生成 查询语句、提供 方法…...

Brother CNC联网数采集和远程控制
兄弟CNC IP地址设定参考:https://www.sohu.com/a/544461221_121353733没有能力写代码的兄弟可以提前下载好网络调试助手NetAssist,这样就不用写代码来测试连接CNC了。 以上是网络调试助手抓取CNC的产出命令,结果有多个行string需要自行解析&…...

Jenkins 编译 Maven 项目提示错误 version 17
在最近使用集成工具的时候,对项目进行编译提示下面的错误信息: maven-compiler-plugin:3.11.0:compile (default-compile) on project mq-service: Fatal error compiling: error: release version 17 not supported 问题和解决 上面提示的错误信息原…...

数据结构——排序算法——堆排序
堆排序过程如下: 1.用数列构建出一个大顶堆,取出堆顶的数字; 2.调整剩余的数字,构建出新的大顶堆,再次取出堆顶的数字; 3.循环往复,完成整个排序。 构建大顶堆有两种方式: 1.从 0 开…...

【Spring事务底层实现原理】
Transactional注解 Spring使用了TransactionInterceptor拦截器,该拦截器主要负责事务的管理,包括开启、提交、回滚等操作。当在方法上添加Transactional注解时,Spring会在AOP框架中对该方法进行拦截,TransactionInterceptor会在该…...

docker快速安装redis,mysql,minio,nacos等常用软件【持续更新】
redis ①拉取镜像 docker pull redis② 创建容器 docker run -d --name redis --restartalways -p 6379:6379 redis --requirepass "PASSWORD"–requirepass “输入你的redis密码” nacos ①:docker拉取镜像 docker pull nacos/nacos-server:1.2.0②…...

SCRUM产品负责人(CSPO)认证培训课程
课程简介 Scrum是目前运用最为广泛的敏捷开发方法,是一个轻量级的项目管理和产品研发管理框架。产品负责人是Scrum的三个角色之一,产品负责人在Scrum产品开发当中扮演舵手的角色,他决定产品的愿景、路线图以及投资回报,他需要回答…...

python连接mysql数据库的练习
一、导入pandas内置的sqlite3模块,连接的信息:ip地址是本机, 端口号port 是3306, 用户user是root, 密码password是123456, 数据库database是lambda-xiaozhang import pymysql# 打开数据库连接,参数1:主机名或IP;参数…...

扩散模型在图像生成中的应用:从真实样例到逼真图像的奇妙转变
一、扩散模型 扩散模型的起源可以追溯到热力学中的扩散过程。热力学中的扩散过程是指物质从高浓度往低浓度的地方流动,最终达到一种动态的平衡。这个过程就是一个扩散过程。 在深度学习领域中,扩散模型(diffusion models)是深度生…...

Windows 打包 Docker 提示环境错误: no DOCKER_HOST environment variable
这个问题应该还是比较常见的。 [ERROR] Failed to execute goal io.fabric8:docker-maven-plugin:0.40.2:build (default) on project mq-service: Execution default of goal io.fabric8:docker-maven-plugin:0.40.2:build failed: No <dockerHost> given, no DOCKER_H…...