嵌入式学习第二十七天!(TCP并发模型)

TCP并发模型:

1. TCP多线程模型:

    缺点:创建线程会带来资源开销,能够实现的并发量比较有限。

2. IO模型:

    1. 阻塞IO:

        没有数据到来时,可以让任务挂起,节省CPU资源开销,提高系统效率

    2. 非阻塞IO:

        程序未接收到数据时一直执行,效率很低

        举例应用:

write.c

#include "head.h"int main(void)
{int fd = 0;char tmpbuff[1024] = {0};mkfifo("/tmp/myfifo", 0664);fd = open("/tmp/myfifo", O_WRONLY);if(fd == -1){perror("fail to open");return -1;}while(1){memset(tmpbuff, 0, sizeof(tmpbuff));gets(tmpbuff);write(fd, tmpbuff, strlen(tmpbuff));}close(fd);return 0;
}

        后面的举例应用的write.c都为上面所示

read.c

#include "head.h"int main(void)
{int fd = 0;int flags = 0;ssize_t nsize = 0;char *pret = NULL;char tmpbuff[1024] = {0};mkfifo("/tmp/myfifo", 0664);fd = open("/tmp/myfifo", O_RDONLY);if(fd == -1){perror("fail to open");return -1;}flags = fcntl(fd, F_GETFL);flags |= O_NONBLOCK;fcntl(fd, F_SETFL, flags);flags = fcntl(0, F_GETFL);flags |= O_NONBLOCK;fcntl(0, F_SETFL, flags);while(1){memset(tmpbuff, 0, sizeof(tmpbuff));pret = gets(tmpbuff);if(pret != NULL){printf("STDIN:%s\n", tmpbuff);}memset(tmpbuff, 0, sizeof(tmpbuff));nsize = read(fd, tmpbuff, sizeof(tmpbuff));if(nsize > 0){printf("RECV:%s\n", tmpbuff);}}close(fd);return 0;
}

        通过fcntl将fd和stdin文件描述符设置为非阻塞IO,所以read.c既可以通过管道接收消息,也可以同终端输入,接收消息,二者不会堵塞。

    3. 异步IO:

        只能绑定一个文件描述符用来读取数据

        举例应用:

read.c

#include "head.h"int fd = 0;void handler(int signo)
{char tmpbuff[1024] = {0};ssize_t nsize = 0;memset(tmpbuff, 0, sizeof(tmpbuff));nsize = read(fd, tmpbuff, sizeof(tmpbuff));if(nsize > 0){printf("RECV:%s\n", tmpbuff);}return;}int main(void)
{int flags = 0;ssize_t nsize = 0;char *pret = NULL;char tmpbuff[1024] = {0};signal(SIGIO, handler);mkfifo("/tmp/myfifo", 0664);fd = open("/tmp/myfifo", O_RDONLY);if(fd == -1){perror("fail to open");return -1;}flags = fcntl(fd, F_GETFL);flags |= O_ASYNC;fcntl(fd, F_SETFL, flags);fcntl(fd, F_SETOWN, getpid());while(1){memset(tmpbuff, 0, sizeof(tmpbuff));gets(tmpbuff);printf("STDIN:%s\n", tmpbuff);}close(fd);return 0;
}

    4. 多路复用:

        1. select:

            1. select监听的集合中的文件描述符有上限限制

            2. select有内核层向用户层数据空间拷贝的过程,占用系统资源开销

                原因:在使用select函数时,会涉及到内核层和用户层之间的数据传输。具体来说:select函数在内核层会监视一组文件描述符的状态变化,并在有变化发生时通知用户层。为了是实现这个功能,内核会定期检测文件描述符的状态,并在发生变化时将相关信息传递给用户层。这个过程涉及到内核层和用户层之间的数据传输,即内核层需要将监视的文件描述符的状态信息传递给用户层。这个传输过程会涉及到系统资源的开销,因为需要进行数据拷贝操作,将内核中的数据拷贝到用户空间,这个数据拷贝的过程会消耗一定的系统资源。

            3. select必须轮询检测产生事件的文件描述符

            4. select只能工作在水平触发模式(低速模式),无法工作在边沿触发模式(高速模式)

                原因:

                    1. 在水平触发模式下,一旦文件描述符中的数据可读或可写,select就会通知用户程序,并且如果这些描述符在之后的select调用中仍然保持可读或可写状态,select会再次通知程序。换句话说,在水平触发模式下,只要描述符的状态处于可读或可写状态,select就会通知程序。

                    2. 在边缘触发模式下,只有当描述符的状态发生变化时才会通知程序,这意味着如果描述符中的数据量发生变化或者有新的数据到达,程序才会被通知,而如果描述符的状态保持不变,即使在之后的select调用中它任然处于可读或可写状态,程序也不会被通知。

            举例应用:

read.c

#include "head.h"int main(void)
{int fd = 0;int flags = 0;ssize_t nsize = 0;char *pret = NULL;fd_set rdfds;fd_set tmpfds;int ret = 0;char tmpbuff[1024] = {0};mkfifo("/tmp/myfifo", 0664);fd = open("/tmp/myfifo", O_RDONLY);if(fd == -1){perror("fail to open");return -1;}FD_ZERO(&rdfds);FD_SET(fd, &rdfds);FD_SET(0, &rdfds);while(1){tmpfds = rdfds;ret = select(fd+1, &tmpfds, NULL, NULL, NULL);if(ret == -1){perror("fail to select");return -1;}if(FD_ISSET(0, &tmpfds)){memset(tmpbuff, 0, sizeof(tmpbuff));gets(tmpbuff);printf("STDIN:%s\n", tmpbuff);}if(FD_ISSET(fd, &tmpfds)){memset(tmpbuff, 0, sizeof(tmpbuff));read(fd, tmpbuff, sizeof(tmpbuff));printf("FIFO:%s\n", tmpbuff);}}close(fd);return 0;
}

        2. poll:

            1. poll有内核层向用户层数据空间拷贝的过程,占用系统资源开销

            2. poll必须轮询检测产生事件的文件描述符

            3. poll只能工作在水平触发模式(低速模式),无法工作在边沿触发模式(高速模式)

            举例应用:

read.c

#include "head.h"int main(void)
{int fd = 0;int ret = 0;int flags = 0;ssize_t nsize = 0;struct pollfd fds[2];char tmpbuff[1024] = {0};mkfifo("/tmp/myfifo", 0664);fd = open("/tmp/myfifo", O_RDONLY);if(fd == -1){perror("fail to open");return -1;}fds[0].fd = 0;fds[0].events = POLLIN;fds[1].fd = fd;fds[1].events = POLLIN;while(1){ret = poll(fds, 2, -1);if(ret == -1){perror("fail to poll");return -1;}if(fds[0].revents & POLLIN){memset(tmpbuff, 0, sizeof(tmpbuff));gets(tmpbuff);printf("STDIN:%s\n", tmpbuff);}if(fds[1].revents & POLLIN){memset(tmpbuff, 0, sizeof(tmpbuff));read(fd, tmpbuff, sizeof(tmpbuff));printf("FIFO:%s\n", tmpbuff);}}close(fd);return 0;
}

        3. epoll:

            1. epoll没有文件描述符上限限制

            2. epoll创建内核监听事件表,所以只需要在内核空间完成数据拷贝即可

            3. epoll会将产生事件的文件描述符对应的事件直接返回

            4. epoll可以工作在水平触发模式(默认:低速模式),还可以工作在边沿触发模式(高速模式) 在epoll_events的结构体中的events传入EPOLLIN | EPOLLET即可

            举例应用:

read.c

#include "head.h"int main(void)
{int i = 0;int fd = 0;int epfd = 0;int nready = 0;ssize_t nsize = 0;char tmpbuff[1024] = {0};struct epoll_event env;struct epoll_event retenv[2];mkfifo("/tmp/myfifo", 0664);fd = open("/tmp/myfifo", O_RDONLY);if(fd == -1){perror("fail to open");return -1;}epfd = epoll_create(2);if(epfd == -1){perror("fail to epoll_create");return -1;}env.data.fd = 0;env.events = EPOLLIN;epoll_ctl(epfd, EPOLL_CTL_ADD, 0, &env);env.data.fd = fd;env.events = EPOLLIN;epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &env);while(1){nready = epoll_wait(epfd, retenv, 2, -1);if(nready == -1){perror("fail to epoll_wait");return -1;}for(i = 0; i < nready; i++){if(retenv[i].data.fd == 0){memset(tmpbuff, 0, sizeof(tmpbuff));gets(tmpbuff);printf("STDIN:%s\n", tmpbuff);}else if(retenv[i].data.fd == fd){memset(tmpbuff, 0, sizeof(tmpbuff));read(fd, tmpbuff, sizeof(tmpbuff));printf("FIFO:%s\n", tmpbuff);}}}close(fd);return 0;
}

3. 函数接口:

    1. select:

int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);

        功能:select监听文件描述符集合中是否有文件描述编程ready状态

        参数:

            nfds:最大文件描述符的值+1

            reafds:读文件描述符集合

            writefds:写文件描述符集合

            exceptfds:其余文件描述符集合

            timeout:等待的时长

                        NULL:一直等待

        返回值:

            成功返回文件描述符集合中的文件描述符个数
            失败返回-1

    void FD_CLR(int fd, fd_set *set);

                功能:判断文件描述符fd是否仍在集合中

    void FD_SET(int fd, fd_set *set);

                功能:将文件描述符fd加入到集合中

    int  FD_ISSET(int fd, fd_set *set);

                功能:判断文件描述符fd是否仍在集合中

    void FD_ZERO(fd_set *set);

                功能:将文件描述符集合清0

    2. poll:

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

        功能:监听文件描述符集合是否有事件发生

        参数:

            fds:监听文件描述符集合是否有时间发生

            nfds:监听文件描述符集合元素个数

            timeout:等待时间(-1一直等待)

struct pollfd {int   fd;         /* file descriptor */short events;     /* requested events */short revents;    /* returned events */
};

                fd:监听的文件描述

                events:要监听的事件,POLLIN:是否可读,POLLOUT:是否可写

                revents:实际产生的事件

    3. epoll:

        1. epoll_create:
int epoll_create(int size);

            功能:创建一张内核事件表

            参数:

                size:事件的个数

            返回值:

                成功返回文件描述符
                失败返回-1

        2. epoll_ctl:
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

            功能:维护epoll时间表

            参数:

                epfd:事件表的文件描述符

                op:

                    EPOLL_CTL_ADD     添加事件

                    EPOLL_CTL_MODE  修改事件

                    EPOLL_CTL_DEL      删除事件

                fd:操作的文件描述符

                events:事件对应的事件

typedef union epoll_data {void    *ptr;in    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 */
};

            返回值:

                成功返回0 
                失败返回-1 

        3. epoll_wait:
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

            功能:监听事件表中的事件

            参数:

                epfd:文件描述符

                events:存放实际产生事件的数组空间首地址

                maxevents:最多存放事件的个数

                timeout:设定监听的时间(超过该时间则不再监听)

                        -1:一直监听直到有事件发生

            返回值:

                成功返回产生事件的文件描述符个数
                失败返回-1 
                如果时间达到仍没有事件发生返回0

4. 练习作业:

        1. 编写TCP并发模型之select模型

client.c

#include "head.h"int CreateTcpClient(char *pip, int port)
{int ret = 0;int sockfd = 0;struct sockaddr_in seraddr;sockfd = socket(AF_INET, SOCK_STREAM, 0);if (-1 == sockfd){perror("fail to socket");return -1;}seraddr.sin_family = AF_INET;seraddr.sin_port = htons(port);seraddr.sin_addr.s_addr = inet_addr(pip);ret = connect(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));if (-1 == ret){perror("fail to connect");return -1;}return sockfd;
}int main(void)
{int sockfd = 0;char tmpbuff[4096] = {"hello world"};int cnt = 0;ssize_t nsize = 0;sockfd = CreateTcpClient("192.168.1.125", 50000);while (1){memset(tmpbuff, 0, sizeof(tmpbuff));sprintf(tmpbuff, "hello world --- %d", cnt);cnt++;nsize = send(sockfd, tmpbuff, strlen(tmpbuff), 0);if (-1 == nsize){perror("fail to send");return -1;}memset(tmpbuff, 0, sizeof(tmpbuff));nsize = recv(sockfd, tmpbuff, sizeof(tmpbuff), 0);if (-1 == nsize){perror("fail to recv");return -1;}printf("RECV:%s\n", tmpbuff);}close(sockfd);return 0;
}

        后面的client.c都为上面所示

server.c

#include "head.h"int CreateListenSocket(char *pip, int port)
{int ret = 0;int sockfd = 0;struct sockaddr_in serveraddr;sockfd = socket(AF_INET, SOCK_STREAM, 0);if(sockfd == -1){perror("fail to socket");return -1;}serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(port);serveraddr.sin_addr.s_addr = inet_addr(pip);ret = bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));if(ret == -1){perror("fail to bind");return -1;}ret =listen(sockfd, 10);if(ret == -1){perror("fail to listen");return -1;}return sockfd;
}int HandleTcpClient(int confd)
{char tmpbuff[4096] = {0};ssize_t nsize = 0;memset(tmpbuff, 0, sizeof(tmpbuff));nsize = recv(confd, tmpbuff, sizeof(tmpbuff), 0);if(nsize == -1){perror("fail to recv");return -1;}else if(nsize == 0){return 0;}sprintf(tmpbuff, "%s ------echo", tmpbuff);nsize = send(confd, tmpbuff, strlen(tmpbuff), 0);if(nsize == -1){perror("fail to send");return -1;}return nsize;}int main(void)
{int i = 0;int ret = 0;int confd = 0;int sockfd = 0;fd_set rdfds;fd_set tmpfds;int maxfd = 0;sockfd = CreateListenSocket("192.168.1.125", 50000);FD_ZERO(&rdfds);FD_SET(sockfd, &rdfds);maxfd = sockfd;while(1){tmpfds = rdfds;ret = select(maxfd+1, &tmpfds, NULL, NULL, NULL);if(ret == -1){perror("fail to select");return -1;}if(FD_ISSET(sockfd, &tmpfds)){confd = accept(sockfd, NULL, NULL);if(confd == -1){perror("fail to accept");FD_CLR(sockfd, &rdfds);close(sockfd);continue;}FD_SET(confd, &rdfds);maxfd = maxfd > confd ? maxfd : confd;}for(i = sockfd+1; i <= maxfd; i++){if(FD_ISSET(i, &tmpfds)){ret = HandleTcpClient(i);if(ret == -1){fprintf(stderr, "handle client fialed!\n");FD_CLR(i, &rdfds);close(i);continue;}else if(ret == 0){fprintf(stderr, "client disconnected!\n");FD_CLR(i, &rdfds);close(i);continue;}}}}close(confd);close(sockfd);return 0;
}

        2. 编写TCP并发模型之poll模型

server.c

#include "head.h"int CreateListenSocket(char *pip, int port)
{int ret = 0;int sockfd = 0;struct sockaddr_in serveraddr;sockfd = socket(AF_INET, SOCK_STREAM, 0);if(sockfd == -1){perror("fail to socket");return -1;}serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(port);serveraddr.sin_addr.s_addr = inet_addr(pip);ret = bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));if(ret == -1){perror("fail to bind");return -1;}ret =listen(sockfd, 10);if(ret == -1){perror("fail to listen");return -1;}return sockfd;
}int HandleTcpClient(int confd)
{char tmpbuff[4096] = {0};ssize_t nsize = 0;memset(tmpbuff, 0, sizeof(tmpbuff));nsize = recv(confd, tmpbuff, sizeof(tmpbuff), 0);if(nsize == -1){perror("fail to recv");return -1;}else if(nsize == 0){return 0;}sprintf(tmpbuff, "%s ------echo", tmpbuff);nsize = send(confd, tmpbuff, strlen(tmpbuff), 0);if(nsize == -1){perror("fail to send");return -1;}return nsize;}int InitFds(struct pollfd *fds, int maxlen)
{int i = 0;for(i = 0; i < maxlen; i++){fds[i].fd = -1;}return 0;
}int AddFds(struct pollfd *fds, int maxlen, int fd, short env)
{int i = 0;for(i = 0; i < maxlen; i++){if(fds[i].fd == -1){fds[i].fd = fd;fds[i].events = env;break;}}if(i == maxlen){return -1;}return 0;
}int DeleteFds(struct pollfd *fds, int maxlen, int fd)
{int i = 0;for(i = 0; i < maxlen; i++){if(fds[i].fd == fd){fds[i].fd = -1;break;}}return 0;
}int main(void)
{int i = 0;int ret = 0;int nready = 0;int confd = 0;int sockfd = 0;struct pollfd fds[1024];sockfd = CreateListenSocket("192.168.1.125", 50000);InitFds(fds, 1024);AddFds(fds, 1024, sockfd, POLLIN);while(1){nready = poll(fds, 1024, -1);if(nready == -1){perror("fail to poll");return -1;}for(i = 0; i < 1024; i++){if(fds[i] == -1){continue;}if(fds[i].revents & POLLIN && fds[i].fd == sockfd){confd = accept(sockfd, NULL, NULL);if(confd == -1){perror("fail to accept");close(sockfd);DeleteFds(fds, 1024, sockfd);continue;}AddFds(fds, 1024, confd, POLLIN);}else if(fds[i].revents & POLLIN && fds[i].fd != sockfd){ret = HandleTcpClient(fds[i].fd);if(ret == -1){fprintf(stderr, "handle tcp client failed!\n");close(fds[i].fd);DeleteFds(fds, 1024, fds[i].fd);continue;}else if(ret == 0){fprintf(stderr, "client disconnected!\n");close(fds[i].fd);DeleteFds(fds, 1024, fds[i].fd);continue;}}}}close(confd);close(sockfd);return 0;
}

        3. 编写TCP并发模型之epoll模型

server.c

#include "head.h"int CreateListenSocket(char *pip, int port)
{int ret = 0;int sockfd = 0;struct sockaddr_in serveraddr;sockfd = socket(AF_INET, SOCK_STREAM, 0);if(sockfd == -1){perror("fail to socket");return -1;}serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(port);serveraddr.sin_addr.s_addr = inet_addr(pip);ret = bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));if(ret == -1){perror("fail to bind");return -1;}ret =listen(sockfd, 10);if(ret == -1){perror("fail to listen");return -1;}return sockfd;
}int HandleTcpClient(int confd)
{char tmpbuff[4096] = {0};ssize_t nsize = 0;memset(tmpbuff, 0, sizeof(tmpbuff));nsize = recv(confd, tmpbuff, sizeof(tmpbuff), 0);if(nsize == -1){perror("fail to recv");return -1;}else if(nsize == 0){return 0;}sprintf(tmpbuff, "%s ------echo", tmpbuff);nsize = send(confd, tmpbuff, strlen(tmpbuff), 0);if(nsize == -1){perror("fail to send");return -1;}return nsize;}int AddFd(int epfd, int fd, uint32_t env)
{int ret = 0;struct epoll_event tmpenv;tmpenv.data.fd = fd;tmpenv.events = env;ret = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &tmpenv);if(ret == -1){perror("fail to epoll_ctl");return -1;}return 0;
}int DelFd(int epfd, int fd)
{int ret = 0;ret = epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);if(ret == -1){perror("fail to epoll_ctl");return -1;}return 0;
}int main(void)
{int i = 0;int ret = 0;int nready = 0;int confd = 0;int sockfd = 0;struct epoll_event retenv[1024];int epfd = 0;epfd = epoll_create(1024);if(epfd == -1){perror("fail to epoll_create");return -1;}sockfd = CreateListenSocket("192.168.1.155", 50000);AddFd(epfd, sockfd, EPOLLIN);while(1){nready = epoll_wait(epfd, retenv, 1024, -1);if(nready == -1){perror("fail to epoll");return -1;}for(i = 0; i < nready; i++){if(retenv[i].data.fd == sockfd){confd = accept(sockfd, NULL, NULL);if(confd == -1){perror("fail to accept");DelFd(epfd, sockfd);close(sockfd);continue;}AddFd(epfd, confd, EPOLLIN);}else if(retenv[i].data.fd != sockfd){ret = HandleTcpClient(retenv[i].data.fd);if(ret == -1){fprintf(stderr, "handle tcp client failed!\n");DelFd(epfd, retenv[i].data.fd);close(retenv[i].data.fd);continue;}else if(ret == 0){fprintf(stderr, "client disconnected!\n");DelFd(epfd, retenv[i].data.fd);close(retenv[i].data.fd);continue;}}}}close(epfd);close(sockfd);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/277035.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

物理隔离条件下,如何安全高效地进行内外网文件导入导出?

内外网文件导入导出通常指的是在内部网络&#xff08;内网&#xff09;和外部网络&#xff08;外网&#xff09;之间传输文件的过程。这在企业环境中尤其常见&#xff0c;因为内部网络通常包含敏感数据&#xff0c;而外部网络&#xff08;如互联网&#xff09;则允许更广泛的访…

Apache zookeeper kafka 开启SASL安全认证

背景&#xff1a;我之前安装的kafka没有开启安全鉴权&#xff0c;在没有任何凭证的情况下都可以访问kafka。搜了一圈资料&#xff0c;发现有关于sasl、acl相关的&#xff0c;准备试试。 简介 Kafka是一个高吞吐量、分布式的发布-订阅消息系统。Kafka核心模块使用Scala语言开发…

MySql入门教程--MySQL数据库基础操作

꒰˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好&#xff0c;我是xiaoxie.希望你看完之后,有不足之处请多多谅解&#xff0c;让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN …

k8s的pod和svc相互访问时网络链路解析

k8s的pod和svc相互访问时网络链路解析 1. k8s环境中pod相互访问1.1. k8s中pod相互访问的整体流程1.2. k8s的相同机器的不同pod相互访问1.3. k8s的不同机器的不同pod相互访问 2. k8s访问svc2.1 nat操作2.2 流量进入到后端pod 3. 疑问和思考3.1 访问pod相互访问为什么不用做nat?…

【InternLM 实战营笔记】基于 InternLM 和 LangChain 搭建MindSpore知识库

InternLM 模型部署 准备环境 拷贝环境 /root/share/install_conda_env_internlm_base.sh InternLM 激活环境 conda activate InternLM 安装依赖 # 升级pip python -m pip install --upgrade pippip install modelscope1.9.5 pip install transformers4.35.2 pip install…

数据结构之单链表

目录 1.问题引入 2.主题介绍 2.1链表的概念和结构 2.2链表的分类 2.3单链表的实现 2.3.1接口实现 2.3.2函数实现 2.3.3函数测试 3.小结 halo&#xff0c;又和大家见面了&#xff0c;今天要给大家分享的是单链表的知识&#xff0c;跟着我的脚步&#xff0c;包学包会哦~ …

中电金信:技术实践|Flink维度表关联方案解析

导语&#xff1a;Flink是一个对有界和无界数据流进行状态计算的分布式处理引擎和框架&#xff0c;主要用来处理流式数据。它既可以处理有界的批量数据集&#xff0c;也可以处理无界的实时流数据&#xff0c;为批处理和流处理提供了统一编程模型。 维度表可以看作是用户来分析数…

人工智能|机器学习——K-means系列聚类算法k-means/ k-modes/ k-prototypes/ ......(划分聚类)

1.k-means聚类 1.1.算法简介 K-Means算法又称K均值算法&#xff0c;属于聚类&#xff08;clustering&#xff09;算法的一种&#xff0c;是应用最广泛的聚类算法之一。所谓聚类&#xff0c;即根据相似性原则&#xff0c;将具有较高相似度的数据对象划分至同一类簇&#xff0c;…

精读《精通 console.log》

1 引言 本周精读的文章是 Mastering JS console.log like a Pro&#xff0c;一起来更全面的认识 console 吧&#xff01; 2 概述 & 精读 console 的功能主要在于控制台打印&#xff0c;它可以打印任何字符、对象、甚至 DOM 元素和系统信息&#xff0c;下面一一介绍。 c…

PSCA电源控制集成之电压和电源域边界

电压域之间的跨越必须是异步的。电源域之间的跨越可以是同步的&#xff0c;也可以是异步的。 在电压域或异步电源域之间的边界处&#xff0c;需要使用域桥来实现所需的协议。 对于电压域之间的边界&#xff0c;或者是异步电源域之间的边界&#xff0c;域桥被分割成两半&#…

基于springboot的七彩云南文化旅游网站的设计与实现(论文+源码)_kaic

摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装七彩云南文化旅游网站软件来发挥其高效地信息处理的作用&am…

Linux系列

安装系列 1.MySQL安装 我们要通过rpm&#xff0c;进行MySQL数据库的安装&#xff0c;主要的步骤如下&#xff1a; rpm -qa 查询当前系统中安装的所有软件 rpm -qa | grep mysql 查询当前系统中安装的名称带mysql的软件 rpm -…

七月论文审稿GPT第3.2版和第3.5版:通过paper-review数据集分别微调Mistral、gemma

前言 我司第二项目组一直在迭代论文审稿GPT(对应的第二项目组成员除我之外&#xff0c;包括&#xff1a;阿荀、阿李、鸿飞、文弱等人)&#xff0c;比如 七月论文审稿GPT第1版&#xff1a;通过3万多篇paper和10多万的review数据微调RWKV七月论文审稿GPT第2版&#xff1a;用一万…

Android Kotlin知识汇总(三)Kotlin 协程

Kotlin的重要优势及特点之——结构化并发 Kotlin 协程让异步代码像阻塞代码一样易于使用。协程可大幅简化后台任务管理&#xff0c;例如网络调用、本地数据访问等任务的管理。本主题介绍如何使用 Kotlin 协程解决以下问题&#xff0c;从而让您能够编写出更清晰、更简洁的应用代…

【蓝桥杯选拔赛真题67】python奇偶数位相乘 第十五届青少年组蓝桥杯python选拔赛真题 算法思维真题解析

目录 python奇偶数位相乘 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 七、 推荐资料 1、蓝桥杯比赛 2、考级资料 3、其它资料 python奇偶数位相乘 第十五届蓝桥杯青少年组python比赛选拔赛真题 一…

Qt教程 — 3.4 深入了解Qt 控件:Input Widgets部件(3)

目录 1 Input Widgets简介 2 如何使用Input Widgets部件 2.1 Dial 组件-模拟车速表 2.2 QScrollBar组件-创建水平和垂直滚动条 2.3 QSlider组件-创建水平和垂直滑动条 2.4 QKeySequenceEdit组件-捕获键盘快捷键 Input Widgets部件部件较多&#xff0c;将分为三篇文章介绍…

前端和后端权限控制【笔记】

前端权限设置【笔记】 前言版权推荐前端权限设置需求效果实现资源 后端权限控制1.给所有前端请求都携带token2.添加拦截器3.配置到WebMvcConfiguration4.更多的权限验证 最后 前言 2024-3-15 18:27:26 以下内容源自《【笔记】》 仅供学习交流使用 版权 禁止其他平台发布时删…

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:NavDestination)

作为子页面的根容器&#xff0c;用于显示Navigation的内容区。 说明&#xff1a; 该组件从API Version 9开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 该组件从API Version 11开始默认支持安全区避让特性(默认值为&#xff1a;expandSaf…

ubuntu安装docker的详细教程

检查卸载老版本docker ubuntu下自带了docker的库,不需要添加新的源。 但是ubuntu自带的docker版本太低,需要先卸载旧的再安装新的。 注:docker的旧版本不一定被称为docker,docker.io 或 docker-engine也有可能,所以卸载的命令为: sudo apt-get remove -y docker docke…

部署prometheus+Grafana可视化仪表盘监控服务

一、部署prometheus及监控仪表盘 简介 Prometheus是开源监控报警系统和时序列数据库(TSDB)。 Prometheus的基本原理是通过HTTP协议周期性抓取被监控组件的状态&#xff0c;任意组件只要提供对应的HTTP接口就可以接入监控&#xff0c;输出被监控组件信息的HTTP接口被叫做expo…