网络编程4-并发服务器、阻塞与非阻塞IO、信号驱动模型、IO多路复用..

一、并发服务器

1、单循环服务器(顺序处理)        

        一次只能处理一个客户端连接,只有当前客户端断开连接后,才能接受新的客户端连接

2、多进程/多线程并发服务器

while(1) {
connfd = accept(listenfd);
pid = fork();  // 或 pthread_create()
if (pid == 0) {
// 子进程/线程处理通信
recv(connfd, ...);
send(connfd, ...);
close(connfd);
exit(0); // 或 pthread_exit
}
close(connfd); // 父进程关闭已交给子进程的 connfd
}

优点:

  • 实现真正并发

  • 客户端可长时间通信

缺点:

  • 创建/销毁进程或线程开销大

  • 资源占用高(内存、CPU)

  • 存在僵尸进程问题(需 waitpid() 回收)

二、IO 模型分类(5种)

1、阻塞IO模型

  • 常见阻塞IO模型:
    • i--读 scanf、getchar、fgets、read、recv
    • o--写 管道:读端存在,写管道 ​写操作阻塞>>>>内存不足,写不进去便阻塞了

  • 优点:简单、方便、要等 效率不高

2、 非阻塞IO模型

1)以读为例:

  • 特点:需要不停去看,资源开销大

2)实现方法

方法一:open() 时指定

int fd = open("fifo", O_RDONLY | O_NONBLOCK);

方法二:运行时用 fcntl() 修改

int flag = fcntl(fd, F_GETFL, 0);
flag |= O_NONBLOCK;
fcntl(fd, F_SETFL, flag);

  • 注意事项
  •  适用于 read/write 等系统调用。 对 recv() 可使用 MSG_DONTWAIT 标志实现非阻塞

3)示例

方法一

方法二

3、信号驱动IO模型

1)使用 SIGIO 信号通知数据到达,异步但支持有限

  • 有数据发个信号,然后系统调用
  • 通知粒度粗:仅能告知 “有 IO 事件”,无法区分事件类型与细节

2)利用函数:fcntl 实现

3)实现步骤

// 1. 设置文件描述符支持异步通知
int flags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, flags | O_ASYNC);

// 2. 设置信号接收者(当前进程)
fcntl(fd, F_SETOWN, getpid());

// 3. 注册信号处理函数
signal(SIGIO, sig_handler);

  • 不足之处
    • 支持的文件类型有限(如 socket、tty)

    • 不适合大量连接场景

    • 实际应用较少

4)示例

4、异步 IO 模型

信号驱动IO和一步IO区别

核心结论信号驱动 IO异步 IO
异步能力的完整性“半异步”:仅解决 “IO 就绪通知”,未解决 “数据拷贝异步”“全异步”:从 “IO 就绪” 到 “数据拷贝完成” 全程异步
内核与应用的职责划分内核仅通知 “就绪”,数据拷贝需应用程序主动做内核包办 “就绪检测 + 数据拷贝”,应用程序仅用结果
工业界定位早期异步 IO 的过渡方案,已被淘汰现代高并发 / 高性能 IO 的标准方案

        简单来说:信号驱动 IO 是 “让内核喊你‘饭好了’,但你得自己去盛饭”;现代异步 IO 是 “内核把‘饭盛好端到你面前’,你直接吃就行”—— 后者才是真正意义上 “无感知等待、无主动操作” 的异步 IO

5、IO多路复用模型

1)概念

        一个线程监控多个文件描述符(fd),当其中任意一个就绪时通知程序进行处理

        n个客户端-->>用一个线程或进程服务器去答复

        优点:避免创建大量线程/进程,节省资源,适合高并发场景(如 Web 服务器)

        常见函数:select()、poll()、epoll()

2)函数介绍

① select

头文件:        #include <sys/select.h>

函数原型:

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

功能:        实现IO多路复用

参数:

        nfds //是关心的文件描述符中最大的那个文件描述符 + 1

        readfds //代表 要关心 的 读操作的文件描述符的集合

        writefds //代表 要关心 的 写操作的文件描述符的集合 >>> 与read类似

        exceptfds //代表 要关心 的 异常的文件描述符的集合 >>> 与read类似(error--2)

        timeout //超时 设置一个超时时间

                //NULL 表示select是一个阻塞调用

    {0,0}:非阻塞效果

    {sec, usec}:指定超时

                时间最小单位写到ms

返回值:        

                成功:就绪的 fd 数量(>0)

                超时:返回 0

                失败:返回 -1

辅助宏函数:

                FD_ZERO(fd_set *set);                // 清空集合
FD_SET(int fd, fd_set *set);         // 添加 fd 到集合
FD_CLR(int fd, fd_set *set);         // 从集合中移除 fd
FD_ISSET(int fd, fd_set *set);      // 判断 fd 是否在集合中

基本实现流程

文字版过程

  • 建立一张表 >>>监控 目前只关心读
    • fd_set readfds;一张表
    • FD_ZERO(&readfds);清空表(初始化)
  • 将要监控的文件描述符 添加到表中
    • FD_SET(0,&readfds);//stdin
    • FD_SET(fd,&readfds);//建的管道或者文件描述符
  • 准备参数
    • maxfds 是关心的文件描述符中最大的那个文件描述符 + 1
      • int maxfds = fd + 1;
    • 每次系统调用只会留下就绪的文件描述符(每次监控都会重新遍历一遍)
      • fd_set backfds; //设置这个等于最初的表
  • 一般在循环内进行系统调用
  • 具体内容如下
  • 最前面建立tcp网络连接的基本步骤

  • 利用select函数实现步骤

  • 加上定时定次功能

优点
  • 内核负责轮询,减少用户态频繁切换

  • 支持跨平台(Windows/Linux 均可用

缺点
  • 最大监听数受限:FD_SETSIZE 默认 1024(Linux)

  • 每次调用需重置 fd_set:内核会修改集合,必须每次重新 FD_SET

  • 用户态与内核态拷贝开销大

  • 返回后仍需遍历所有 fd 才能知道哪个就绪

  • 效率随 fd 数量增长下降明显

知识点
  • stdin        --->0
  • stdout      --->1
  • error        --->2

② poll

头文件:        #include <poll.h>

函数原型:  int poll(struct pollfd *fds, nfds_t nfds, int timeout);

功能:            实现IO多路复用

参数:        

struct pollfd *fds :struct pollfd {
int   fd;       // 文件描述符
short events;   // 关注的事件(输入)
short revents;  // 实际发生的事件(输出)
};

nfds_t nfds:表示要监控的文件描述符的数量

timeout :时间值 

返回值:        

                成功 表示 就绪的数量 ;0 超时情况下表示 没有就绪实际

                失败 -1

事件标志:

                POLLIN:数据可读(等价于 select 的读)

基本实现流程

优点
  • 无 1024 限制:只要系统允许打开足够多 fd

  • 无需重置集合:eventsrevents 分离

  • 更清晰的事件机制

  • 效率更高:仅遍历传入的数组,不遍历整个 fd 范围

缺点
  • 每次调用仍需将整个 fds[] 拷贝到内核

  • 返回后仍需遍历全部元素查找就绪 fd

  • 时间复杂度仍是 O(n),连接数多时性能下降

③ epoll

< 水平触发 >

        只要缓冲区有数据就持续触发

结果展现

epoll_create                

函数原型:        int epoll_create(int size);

功能:              创建 epoll 实例

参数:              size:提示内核初始分配空间大小(现已忽略)

返回值:          成功  epoll 文件描述符(用于后续操作)

                         失败 -1

注意事项:      使用完需 close(epfd)

epoll_ctl()        

函数原型:        int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

功能:               控制监听列表

参数:              epfd:epoll 句柄(epoll_create 返回

                         op :操作类型

                                EPOLL_CTL_ADD

                                EPOLL_CTL_DEL

                                EPOLL_CTL_MOD

                         fd:要监听的目标文件描述符

                        event:事件结构体   struct epoll_event

返回值:          成功  epoll 文件描述符(用于后续操作)

                         失败 -1

struct epoll_event

epoll_event 结构体:

struct epoll_event {
uint32_t     events;   // 监听的事件类型
epoll_data_t data;     // 用户数据(共用体)
};

typedef union epoll_data {
void    *ptr;
int      fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;

常见事件类型
事件含义
EPOLLIN可读
EPOLLOUT可写
EPOLLRDHUP对端关闭连接(TCP 半关闭)
EPOLLERR错误(自动监听)
EPOLLHUP挂起(自动监听)
EPOLLET边沿触发模式(Edge Triggered)
EPOLLONESHOT触发一次后失效,需重新注册
epoll_wait()         

函数原型:        int epoll_wait(int epfd,
struct epoll_event *events,
int maxevents,
int timeout);

功能:              等待事件发生

参数:              epfd:epoll 句柄(epoll_create 返回                         

         events:用户提供的数组,用于接收就绪事件

                         maxevents:最大接收事件数(通常 10~100

                        timeout:超时(单位 ms )

                                -1:永久阻塞

                                0:非阻塞

                                >0:等待指定毫秒

        ​​​​​​​        ​​​​​​​        ​​​​​​​        

返回值:          成功  就绪事件数量(无需遍历所有 fd)

                         失败 -1

tcp 实现epoll并发服务器

封装添加和删除函数

完整内容

#include "head.h"int add_fd(int listenfd,int epfd)     //将文件描述符添加到 epoll 监控列表
{struct epoll_event ev; //定义结构体ev.events = EPOLLIN; //表示监控可读事件(文件描述符有数据可读时触发)ev.data.fd = listenfd;if (epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev))//epoll_ctl添加、修改、删除监控的文件描述符{perror("epoll_ctl add fail");return -1;}return 0;
}
int del_fd(int fd,int epfd)
{if (epoll_ctl(epfd,EPOLL_CTL_DEL,fd,NULL)){perror("epoll_ctl del fail");return -1;}return 0;}
int main(void)
{int serfd = socket(AF_INET,SOCK_STREAM,0);if (serfd < 0){perror("fail to socke");return -1;}struct sockaddr_in seraddr;seraddr.sin_family = AF_INET;seraddr.sin_port = htons(50000);seraddr.sin_addr.s_addr = inet_addr("127.0.0.1");if (bind(serfd,(const struct sockaddr *)&seraddr,sizeof(seraddr)) < 0){perror("bind fial");return -1;}if (listen(serfd,5) < 0){perror("listen fail");return -1;}struct sockaddr_in cliaddr;bzero(&cliaddr,0);socklen_t len = sizeof(cliaddr);/************正片开始******************/char buf[1024] = {0};int epfd = epoll_create(1); //创建,返回一个用于操作的文件描述符efd//括号内要求大于0的值就行add_fd(serfd,epfd);  //添加serfd到epoll监控int t = 3000;struct epoll_event ret_ev[1024];   //可以容纳的个数while (1){int ret = epoll_wait(epfd,ret_ev,10,t); //等待事件发生,超时时间为3000ms//ret_ev数组用于存储发生的事件//就序最多处理 10 个事件printf("ret = %d\n",ret);if (ret < 0)        //出错处理{perror("epoll fail");return -1;}if (ret > 0)        //遍历每个事件{int i = 0;for (i = 0; i < ret; i++){if (ret_ev[i].data.fd == serfd)    { int connfd = accept(serfd,(struct sockaddr *)&cliaddr,&len);if (connfd < 0){perror("accept fail");return -1;}printf("----client connect---\n");printf("client ip:%s\n",inet_ntoa(cliaddr.sin_addr));printf("port :%d\n",ntohs(cliaddr.sin_port));//添加到表里add_fd(connfd,epfd);}else //如果不是serfd我们就要开始收数据了{recv(ret_ev[i].data.fd,buf,sizeof(buf),0);printf("buf = %s\n",buf); if (0 == strncmp(buf,"quit",4)){del_fd(ret_ev[i].data.fd,epfd);    //从epfd内删除close(ret_ev[i].data.fd);}}}}}close(serfd);return 0;
}
< 边缘触发 >

        仅在状态变化时触发一次(必须配合非阻塞 IO)

        两种情况:

        正常数据:实际只能触发一次,但数据还在,利用循环可以打印出来,但是读完数据就没有了()---n <0

        quit退出:实际只能触发一次,但数据还在,利用循环可以打印出来,读完数据就没有了,---n= 0

主要改变

注意事项:       

                fd 必须设置为 非阻塞

                必须一次性读完所有数据(直到 read() 返回 EAGAIN

                否则会丢失后续事件

结果展现

具体水平触发的代码区别(改动的地方)

完整代码

#include "head.h"
#include <sys/socket.h>
#include <stdio.h>
#include <errno.h>
#include <poll.h>
#include <sys/epoll.h>#include <unistd.h>
#include <fcntl.h>int add_fd(int fd, int epfd)
{struct epoll_event ev;ev.events = EPOLLIN | EPOLLET;// EPOLLET(ET)边缘触发//$$$--改1--$$$ev.data.fd = fd; //标准输入 if ( epoll_ctl(epfd,EPOLL_CTL_ADD, fd, &ev)){perror("epoll_ctl add fail");return -1;}	return 0;
}int del_fd(int fd, int epfd) //删除 
{//struct epoll_event ev;//ev.events = EPOLLIN;//ev.data.fd = fd; //标准输入 if ( epoll_ctl(epfd,EPOLL_CTL_DEL, fd, NULL)){perror("epoll_ctl add fail");return -1;}	return 0;
}//$$$$$$$$$$--改2--$$$$$$$$$$$$$$$
void set_nonblock(int fd)
{int flags = fcntl(fd,F_GETFL);flags = flags | O_NONBLOCK;fcntl(fd,F_SETFL,flags);return;
}int main(int argc, char const *argv[])
{//step1 socket int fd = socket(AF_INET,SOCK_STREAM,0);if (fd < 0){perror("socket fail");return -1;}struct sockaddr_in seraddr;bzero(&seraddr,sizeof(seraddr));seraddr.sin_family = AF_INET;seraddr.sin_port = htons(50000);seraddr.sin_addr.s_addr = inet_addr("127.0.0.1");//step2 bind if (bind(fd,(const struct sockaddr *)&seraddr,sizeof(seraddr)) < 0){perror("connect fail");return -1;}//step3 listenif (listen(fd,5) < 0){perror("listen fail");return -1;}struct sockaddr_in cliaddr;bzero(&cliaddr,0);socklen_t len = sizeof(cliaddr);//1.准备表 int epfd = epoll_create(1);if (epfd < 0){perror("epoll_create fail");return -1;}//2.添加 fd add_fd(fd,epfd);char buf[1024] = {0};struct epoll_event ret_ev[10];while (1){int ret =epoll_wait(epfd,ret_ev,10,-1);if (ret < 0){perror("epoll fail");return -1;}if (ret > 0){int i = 0;for (i = 0; i < ret; ++i){if (ret_ev[i].data.fd == fd) //listenfd {int connfd = accept(fd,(struct sockaddr *)&cliaddr,&len);if (connfd < 0){perror("accept fail");return -1;}printf("---client connect---\n");printf("client ip:%s\n",inet_ntoa(cliaddr.sin_addr));printf("port: %d\n",ntohs(cliaddr.sin_port));//设置非阻塞set_nonblock(connfd);//添加到表中add_fd(connfd,epfd);}else //$$$$$$$$$$--改3--$$$$$$$$$$$$$$${while(1){int n =  recv(ret_ev[i].data.fd,buf,1,0);printf("n = %d buf = %s\n",n,buf);if (n < 0 && errno != EAGAIN) //正常数据{ perror("recv ");del_fd(ret_ev[i].data.fd,epfd);close(ret_ev[i].data.fd);}if (n== 0 || strncmp(buf,"quit",4) == 0) //退出{del_fd(ret_ev[i].data.fd,epfd);close(ret_ev[i].data.fd);}sleep(1);}}}}} return 0;
}

3)函数对比

特性selectpollepoll
平台兼容性高(POSIX)仅 Linux
最大连接数~1024无限制(但性能差)无限制
时间复杂度O(n)O(n)O(1)
用户/内核拷贝每次全量拷贝每次全量拷贝共享内存
是否修改输入参数是(需备份)否(revents 分离)
触发模式仅 LT仅 LTLT + ET
遍历开销高(需遍历所有 fd)中(遍历数组)低(只处理就绪)
适用场景小规模连接、跨平台中小规模连接大规模高并发(如 Nginx)

4)应用建议

场景推荐方案
小型工具程序(<100 连接)select(简单、跨平台)
中等规模服务(几百连接)pollselect
高并发服务器(数千以上)epoll(Linux)
需跨平台(如 Windows)selectlibevent/libuv 封装

5)总结

整体使用思路:

        1.准备监控表

        2.添加监控的文件描述符

        3.调用函数监控事件发生

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

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

相关文章

在 WSL2-NVIDIA-Workbench 中安装Anaconda、CUDA 13.0、cuDNN 9.12 及 PyTorch(含完整环境验证)

在 WSL-NVIDIA-Workbench&#xff08;NVIDIA AI Workbench & Ubuntu 22.04&#xff09;中 安装 Anaconda、CUDA 13.0、cuDNN 9.12 及 PyTorch 步骤也可参阅&#xff1a; 在WSL2-Ubuntu中安装Anaconda、CUDA13.0、cuDNN9.12及PyTorch&#xff08;含完整环境验证&#xf…

Shell编程核心入门:参数传递、运算符与流程控制全解析

Shell编程核心入门&#xff1a;参数传递、运算符与流程控制全解析 在Linux/Unix系统中&#xff0c;Shell作为命令解释器和脚本语言&#xff0c;是自动化运维、批量处理任务的核心工具。掌握Shell脚本的参数传递、运算符使用和流程控制&#xff0c;能让你从“手动执行命令”升级…

如何用 Kotlin 在 Android 手机开发一个应用程序获取网络时间

使用 NTP 协议获取网络时间在 build.gradle 文件中添加以下依赖&#xff1a;implementation commons-net:commons-net:3.6创建 NTP 时间获取工具类&#xff1a;import org.apache.commons.net.ntp.NTPUDPClient import org.apache.commons.net.ntp.TimeInfo import java.net.In…

python智慧交通数据分析可视化系统 车流实时检测分析 深度学习 车流量实时检测跟踪 轨迹跟踪 毕业设计✅

博主介绍&#xff1a;✌全网粉丝50W&#xff0c;前互联网大厂软件研发、集结硕博英豪成立软件开发工作室&#xff0c;专注于计算机相关专业项目实战6年之久&#xff0c;累计开发项目作品上万套。凭借丰富的经验与专业实力&#xff0c;已帮助成千上万的学生顺利毕业&#xff0c;…

计算机视觉第一课opencv(四)保姆级教学

目录 简介 一、轮廓检测 1.查找轮廓的API 2.代码分析 2.1.图像二值化处理 2.2轮廓检测 2.3轮廓绘制 2.4轮廓面积计算 2.5轮廓周长计算 2.6筛选特定面积的轮廓 2.7查找最大面积的轮廓 2.8绘制轮廓的外接圆 2.9绘制轮廓的外接矩形 二、轮廓的近似 三、模板匹配 简…

基于Vue2+elementUi实现树形 横向 合并 table不规则表格

1、实现效果 共N行&#xff0c;但是每一列对应的单元格列数固定&#xff0c;行数不固定2、实现方式说明&#xff1a;使用的是vue2 elementUI表格组件 js实现<template><div class"table-container" ><el-table height"100%" :span-metho…

深度学习在计算机视觉中的应用:对象检测

引言 对象检测是计算机视觉领域中的一项基础任务&#xff0c;目标是在图像或视频帧中识别和定位感兴趣的对象。随着深度学习技术的发展&#xff0c;对象检测的准确性和效率都有了显著提升。本文将详细介绍如何使用深度学习进行对象检测&#xff0c;并提供一个实践案例。 环境准…

node.js 安装步骤

在Node.js中安装包通常通过npm(Node Package Manager)来完成,这是Node.js的包管理工具。以下是安装Node.js和通过npm安装包的基本步骤: 1. 安装Node.js 方法一:使用nvm(Node Version Manager) 推荐使用nvm来安装Node.js,因为它允许你安装多个Node.js版本,并轻松地在…

面试-故障案例解析

一、NFS故障&#xff0c;造成系统cpu使用率低而负载极高。故障概述: 公司使用NFS为web节点提供共享存储服务,某一天下午发现web节点CPU使用率低,而负载极高.登录web节点服务器排查发现后段NFS服务器故障. 影响范围: 网站看不到图片了。 处理流程: 通过ssh登录NFS服务…

医疗AI时代的生物医学Go编程:高性能计算与精准医疗的案例分析(一)

摘要: 随着高通量测序、医学影像和电子病历等生物医学数据的爆炸式增长,对高效、可靠、可扩展的计算工具需求日益迫切。Go语言凭借其原生并发模型、卓越的性能、简洁的语法和强大的标准库,在生物医学信息学领域展现出独特优势。本文以“生物医学Go编程探析”为主题,通过三个…

针对 “TCP 连接建立阶段” 的攻击

针对 “TCP 连接建立阶段” 的攻击一、定义二、共性防御思路三、攻击手段3.1、SYN 洪水攻击&#xff08;SYN Flood&#xff09;3.2、Land 攻击&#xff08;Land Attack&#xff09;一、定义 什么是针对 “TCP 连接建立阶段” 的攻击&#xff1f;核心特征是利用 TCP “三次握手…

聊一聊 单体分布式 和 微服务分布式

微服务 与 单体架构对比维度单体架构微服务架构​​架构本质​​一个单一的、功能齐全的应用程序一组​​小型、独立​​的服务集合​​开发​​团队工作在同一个代码库&#xff0c;易产生冲突。技术栈统一。每个服务可以由​​ 独立的小团队 ​​负责&#xff0c;允许使用​​…

【C++八股文】计算机网络篇

网络协议核心知识点详解 TCP头部结构 TCP头部包含多个关键字段&#xff0c;每个字段都有其特定作用&#xff1a; 16位源端口&#xff1a;标识发送方应用程序的端口号16位目的端口&#xff1a;标识接收方应用程序的端口号32位序号&#xff1a;保证数据包有序传输的唯一标识32…

小迪Web自用笔记7

游戏一般不走http https协议&#xff0c;一般的抓包工具抓不到。科来&#xff0c;这个工具是从网卡抓包。你一旦打怪数据就会多起来↓但不是很专业。可以抓到https。wep↑这个西东是全部协议都做流量包&#xff0c;你不知道他是从哪儿来的&#xff0c;他全都抓&#xff08;专业…

现代 Linux 发行版为何忽略Shell脚本的SUID位?

在现代Linux系统中&#xff0c;为Shell脚本设置 SUID&#xff08;Set User ID&#xff09; 权限位几乎是无效的。这个看似简单的现象背后&#xff0c;是Linux内核设计者们在安全与便利性之间做出的一个至关重要的历史性抉择。要彻底理解这一点&#xff0c;我们需要深入到内核层…

Qt节点编辑器设计与实现:动态编辑与任务流可视化(一)

文章目录一、项目概述二、整体架构&#xff1a;模型-视图分离的设计哲学1. 模型层&#xff1a;数据与业务逻辑的核心2. 视图层&#xff1a;图形渲染与用户交互3. 交互层&#xff1a;连接模型与视图的桥梁三、核心模块解析1. 样式管理系统&#xff1a;视觉表现的基石2. 图形数据…

MySQL常见报错分析及解决方案总结(4)---ERROR 1040(00000):Too many connections

报错信息&#xff1a;ERROR 1040(00000):Too many comnections异常效果&#xff1a;原因分析&#xff1a;“ERROR 1040 (00000): Too many connections” 是 MySQL 数据库最常见的连接数超限错误&#xff0c;本质是 “当前试图连接数据库的客户端数量&#xff0c;超过了 MySQL …

GRPO(组相对策略优化):大模型强化学习的高效进化

本文由「大千AI助手」原创发布&#xff0c;专注用真话讲AI&#xff0c;回归技术本质。拒绝神话或妖魔化。搜索「大千AI助手」关注我&#xff0c;一起撕掉过度包装&#xff0c;学习真实的AI技术&#xff01; ✨ 1. GRPO概述&#xff1a;重新定义大模型强化学习效率 GRPO&#x…

【Canvas与戳记】蓝底黄面十六角Premium Quality戳记

【成图】【代码】<!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>蓝底黄面十六角Premium Quality戳记 Draft1</title><style ty…

深度学习:洞察发展趋势,展望未来蓝图

在科技飞速发展的当下&#xff0c;深度学习作为人工智能领域的璀璨明星&#xff0c;正以前所未有的速度重塑着各个行业的格局。从日常使用的智能语音助手&#xff0c;到医疗领域精准的疾病诊断&#xff0c;再到自动驾驶汽车对复杂路况的实时感知与决策&#xff0c;深度学习无处…