linux下高级IO模型
高级IO
- 1.高级IO模型
- 基本概念
- 1.1 阻塞IO
- 1.2 非阻塞IO
- 1.3 信号驱动IO
- 1.4 IO多路转接
- 1.5 异步IO
- 2. 模型代码实现
- 2.1 非阻塞IO
- 2.2 多路转接-select
- select函数介绍
- 什么才叫就绪呢?
- demo
- select特点
- 2.3 多路转接-poll
- poll函数介绍
- poll优缺点
- demo
- 2.4 多路转接-epoll(重点)
- epoll系列的接口
- epoll原理
- demo
- epoll工作方式
- ET和LT对比
- ET模式和非阻塞文件描述符的关系
- epoll的使用场景
- epoll的惊群问题
- ET模式的demo
1.高级IO模型
非阻塞IO、记录锁、系统V流机制、IO多路转接、readv和writev函数以及存储映射IO(mmap),这些统称为高级IO。
任何IO过程中,都包含两个步骤。第一个是等待,第二个是拷贝。在实际的应用场景中,等待消耗的时间往往都远高于拷贝的时间。为了让IO更高效,最核心的办法就是让等待的时间尽量少。
基本概念
同步通信和异步通信:
- 同步就是在发出一个调用时,在没有得到结果之前,该调用就不返回。一旦调用返回,就得到返回值了。(由调用者主动等待这个调用的结果)。
- 异步则相反,调用在发出后,这个调用就直接返回了,所以没有返回结果;(当一个异步过程调用发出后,调用者不会立刻得到结果;而是在调用发出后,被调用者通过状态、通知来通知调用者,或者通过回调函数处理这个调用)。
区分 进程同步与互斥:
- 进程/线程同步也是进程/线程之间直接的制约关系。
- 为了完成某种任务而建立的多个线程,需要在某些位置协调他们的工作次序而等待、传递信息所产生的制约关系。
阻塞和非阻塞
- 关注的是程序在等待调用结果(消息、返回值)时的状态。
- 阻塞调用是指在调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。
- 非阻塞调用是指在不能立刻得到结果之前,该调用不会阻塞当前线程。
1.1 阻塞IO
在内核将数据准备好之前,系统调用会一直等待。所有套接字,默认都是阻塞方式。
1.2 非阻塞IO
如果内核没有将数据准备好,系统调用仍然直接返回,并且返回EWOULDBLOCK错误码。
非阻塞IO往往需要程序员循环的方式反复尝试读写文件描述符(轮询的方式)。这对CPU浪费较大。
1.3 信号驱动IO
内核将数据准备好的时候,使用SIGIO信号通知应用程序进行IO操作。
1.4 IO多路转接
虽热从流程图上看起来和阻塞IO类似。实际上最核心在于多路转接能够同时等待多个IO文件描述符的就绪状态。
1.5 异步IO
由内核在数据拷贝完成时,通知应用程序(而信号驱动是告诉应用程序何时可以开始拷贝数据)。
2. 模型代码实现
2.1 非阻塞IO
一个文件描述符,默认都是阻塞IO(比如说read,accept等,都是一直等的)
# include<unistd.h>
# include<fcntl.h>int fcntl(int fd, int cmd, .../ *arg */);
传入的cmd的值不同,后面追加的参数也不相同。
fcntl函数有5个功能:
- 复制一个现有的描述符(cmd=F_DUPFD)
- 获得/设置文件描述符标记(cmd=F_GETFD或F_SETFD)
- 获得/设置文件状态标记(cmd=F_GETFL或F_SETFL )
- 获得/设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN)
- 获得/设置记录锁(cmd=F_GETLK,F_SETLK或F_SETLKW)
将文件描述符设置为非阻塞状态,需要使用第三个个标记。如下:
#include<iostream>
#include<unistd.h>
#include <fcntl.h>
#include <cstring>
using namespace std;void SetNonBlock(int fd)
{int f1 = fcntl(fd, F_GETFL); //使用F_GETFL将当前文件描述符的属性提取出来(这是一个位图)if(f1<0){perror("fcntl");return ;}fcntl(fd, F_SETFL, f1 | O_NONBLOCK); //将该文件状态多设置一个非阻塞,然后设置给fdcout<< " set "<< fd << "nonblock done"<<endl;
}int main()
{char buffer[1024];SetNonBlock(0);while(true){ssize_t n = read(0, buffer, sizeof(buffer)-1);if(n>0){buffer[n-1] = 0;cout<<" echo: "<<buffer<<endl;}else if(n == 0){cout<<"read done!"<<endl;break;}else{// 1.设置成非阻塞之后,如果底层fd数据没有就绪,recv/read/write/send,返回值会以出错的形式返回//2. a 真的出错 b.底层没有就绪// 3.怎么区分程序是真的出错了还是fd没有就绪呢?if(errno==EWOULDBLOCK){cout<<"0 fd data not ready, try again!"<<endl;// do_other_thing();sleep(1);}else{cerr<<" read error, n = "<< n <<"errno code: "<<errno<<", error str"<<strerror(errno)<<endl;}}}return 0;
}
2.2 多路转接-select
select函数介绍
功能:系统调用select函数可以实现多路复用输入/输出模型。
- select系统调用是用来让我们的程序监视多个文件描述符的状态变化的;
- 程序会停在select等待,直到被监视的文件描述符有一个或者多个发生了状态改变。
#include<sys/select.h>int select(int nfds, fd_set *readfds, fd_set *writefds,/fd_set *exceptfds, struct timeval *timeout);
参数解释:
- 参数nfds是需要监视的最大的文件描述符+1;
- rdset,wrset,exset分别是要监视的可读、可写、异常的文件描述符的集合;
- 参数timeout为结构timeval,用来设置select的等待时间
参数timeout解释:
- NULL:表示select()没有timeout,select会一直被阻塞,直到某个文件描述符发生了事件;
- 0:仅检测描述符集合的状态,然后立即返回,并不等待外部事件的状态。
- 特定的时间值:如果在指定的时间段里没有事件发生,select将超时返回
关于fd_set位图的操作接口:
**timeval结构体: **
timeval用于描述一段时间长度,如果在这个时间内,需要监视的文件描述符没有事件发生则函数返回,返回值为0.
函数返回值:
- 执行成功则返回文件描述符状态已改变的个数。
- 如果返回0代表在描述符状态改变前已超过timeout时间,没有返回。
- 如果有错误发生返回-1,错误原因存在errno,此时参数readfds,writefds,exceptfds和timeout的值变成不可预测。
– 错误值可能是:EBADF文件描述符无效或该文件已关闭。EINTR:此调用被信号所中断。EINVAL:参数n为负值。ENOMEM:核心内存不足
什么才叫就绪呢?
读就绪:
- socket内核中,接收缓冲区的字节数,大于等于低水位标记SO_RCVLOWAT。此时可以无阻塞的读该文件描述符,并且返回值大于0;
- socketTCP中,对端关闭连接,此时对socket读,返回0;
- 监听的socket有新的连接请求;
- socket上有未处理的错误;
写就绪:
- socket内核中,发送缓冲区中的可用字节数(发送缓冲区的空闲位置大小),大于等于低水位标记SO_SNDLOWAT,此时可以无阻塞的写,并且返回值大于0;
- socket的写操作被关闭(close或者shutdown)。对一个写操作被关闭的socket进行读写,会触发SIGPIPE信号。
- socket使用非阻塞connect连接成功或者失败之后;
- socket有未读取的错误;
异常就绪:
- socket上收到带外数据(和TCP紧急模式相关);
带外数据解释
demo
连接逻辑:
使用select去等待fd的状态改变,当状态改变时,使用事件派发器去派发任务!
使用telnet命令连接8080号端口,进行发消息
源码地址
select特点
特点:
- 可监控的文件描述符取决于sizeof(fd_set)的值。
- 将fd加入select监控集的同时,还要再使用一个数据结构array保存放到select监控集的fd。
– 一个作用是用于再select返回后,array作为源数据和fd_set进行FD_ISSET判断
–另一个作用是rfds是输入输出型参数,select返回后,会将以前的值清空,因此每次开始时需要重新设置rfds,这就需要用到这个辅助数组。
缺点:
- 每次调用select,都要手动设置fd集合。麻烦
- 每次调用select,都需要把fd集合从用户态拷贝到内核态。当fd很多时候,开销大。
- 每次调用都需要在内核遍历传进来的所有fd。当fd很多时候,开销大。
- 支持的文件描述符有限。
2.3 多路转接-poll
poll函数介绍
poll函数是select的改进。
#include<poll.h>
int poll(struct pollfd* fds, nfds_t nfds, int timeout);
struct pollfd结构体:
参数说明:
- fds是一个poll函数监听的结构列表。每一个元素中,包含了三部分内容:文件描述符,监听的事件集合,返回的事件集合。
- nfds表示fds数组的长度
- timeout表示poll函数超时时间,单位是毫秒
注意:监听设置在events里面,返回的结果在revents里面查
events和revents的事件值:
事件 | 描述 | 是否可作为输入 | 是否可作为输出 |
---|---|---|---|
POLLIN | 数据(包括普通数据和优先数据)可读 | 是 | 是 |
POLLRDNORM | 普通数据可读 | 是 | 是 |
POLLRDBAND | 优先级带数据可读(Linux不支持) | 是 | 是 |
POLLPRI | 高优先级数据可读,比如TCP带外数据 | 是 | 是 |
POLLOUT | 数据(包括普通数据和优先数据)可写 | 是 | 是 |
POLLWRNORM | 数据可写 | 是 | 是 |
POLLWRBAND | 优先级带数据可读 | 是 | 是 |
POLLRDHUP | TCP连接被对方关闭,或者对方关闭了写操作,由GNU引入 | 是 | 是 |
POLLERR | 错误 | 否 | 是 |
POLLHUP | 挂起。比如管道的写端被关闭后,读端描述符上将收到POLLHUP事件 | 否 | 是 |
POLLNVAL | 文件描述符没有打开 | 否 | 是 |
返回结果:
- 返回值小于0, 表示出错
- 返回值等于0,表示poll函数等待超时
- 返回值大于0, 表示poll由于监听的文件描述符就绪而返回。
poll优缺点
优点:
select需要使用三个指针参数,poll仅仅使用一个就可以了
- pollfd结构体包含了要监视的event和要发生的event,不再使用值传递的方式。
- poll没有最大数量的限制
缺点:
poll监听的文件描述符过多时:
- 和select函数一样,poll返回后,需要轮询pollfd来获取就绪的描述符。
- 每次调用pollfd都需要把大量的pollfd结构从用户态拷贝到内核中。
- 同时连接的大量客户端在同一时刻可能只有很少的处于就绪状态,因此随着监视描述符的增长,其效率会线性下降。
demo
同select一样,只不过修改成了poll逻辑的代码。
源码
2.4 多路转接-epoll(重点)
由poll改进来的,兼顾多路转接的所有优点。
epoll系列的接口
//常见一个epoll的句柄
int epoll_create(int size);
参数说明:
- size参数可忽略。
- 使用完后,必须调用close()关闭。
//epoll事件注册函数。
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
参数说明:
- 不同于select()是在监听事件时告诉内核要监听什么类型的事件,而是在这里先注册要监听的事件类型。
- 第一个参数是epoll的句柄。
- 第二个参数表示动作,三个宏来表示。
三个宏:
EPOLL_CTL_ADD:注册新的fd到epfd中;
EPOLL_CTL_MOD:修改已经注册的fd的监听事件;
EPOLL_CTL_DEL:从epfd中删除一个fd; - 第三个参数是需要监听的fd。
- 第四个参数是告诉内核需要监听什么事情
struct epoll_ecent结构体:
events宏:
- EPOLLIN:表示对应的文件描述符可以读。
- EPOLLOUT:表示对应的文件描述符可以写。
- EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外的数据到来)。
- EPOLLERR:表示对应的文件描述符发生错误;
int epoll_wait(int epfd, struct epoll_event* event, int maxevents, int timeout);
参数解释:
- 参数events是分配好的epoll_event结构体数组;
- epoll会把发生的事件赋值到events数组中(event不能为空)。
- maxevents告知内核这个events有多大,这个maxevents的值不能大于创建epoll_create()时的size。
- timeout是超时时间(毫秒),0会立即返回,-1是永久阻塞。
- 如果调用成功,返回准备好的文件描述符数目,如果是0表示超时。小于0表示函数失败。
epoll原理
- 每一个epoll对象都有一个独立的eventpoll结构体,用于用于存放通过epoll_ctl方法向epoll对象添加进来的事件。
- 这些事件会挂载在红黑树中
- 所有添加的epoll中的事件都会与设备驱动程序建立回调关系(当事件就绪时,会调用这个回调方法)
- 这个回调方法会将发生的事件添加到rdlist双链表(就绪列表)中
- 在epoll中,对于每一个事件,都会建立一个epitm结构体。
- 当调用epoll_wait检查是否有事件发生时,只需要检查eventpoll对象中的rdlist双链表中是否有epitem元素即可。
- 如果rdlist不为空,则把发生的事件复制到用户态,同时将事件数量返回给用户。(时间复杂度O(1))。
总结一下:三部曲
- 调用epoll_create创建一个epoll句柄;
- 调用epoll_ctl,将要监控的文件描述符进行注册;
- 调用epoll_wait,等待文件描述符就绪;
demo
epoll源码
epoll工作方式
水平触发(LT)和边缘触发(ET)
LT模式:
- 当epoll检测到socket上事件就绪的时候,可以不立刻进行处理或者只处理一部分。
- 如,缓冲区有2k数据,读了1k,缓冲区还剩1k,第二次调用epoll_wait时,epoll_wait仍然会立刻返回并通知socket读事件就绪。
- 直到缓冲区上所有的数据都被处理完,epoll_wait才不会立刻返回。
- 支持阻塞读写和非阻塞读写
ET模式:
如果在第一步将socket添加到epoll描述符的时候使用了EPOLLET标志,epoll进入ET工作模式。
- 当epoll检测到socket上事件就绪时,必须立刻处理。
- 如,缓冲区有2k数据,读了1k,缓冲区还剩1k的数据,在第二次调用epoll_wait的时候,epoll_wait不会再返回了。
- 也就是说,ET模式下,文件描述符上的事件就绪后,只有一次处理机会。
- ET的性能比LT的性能更高(epoll_wait返回的次数少了很多)。Ngnix默认采用ET模式使用epoll。
- 只支持非阻塞的读写。
注意:select和poll工作在LT模式,epoll二者都支持
ET和LT对比
LT是epoll的默认行为。**使用ET能够减少epoll触发的次数。但是代价就是强迫程序一次响应就绪过程中就把所有的数据都处理完。**相当于一个文件描述符就绪之后,不会反复被提示就绪,看起来比LT更高效一些。但是在LT情况下如果也能做到每次就绪的文件描述符都立刻处理,不让这个就绪被重复提示的话,其实性能也是一样的。
另外ET的代码复杂度高。
ET模式和非阻塞文件描述符的关系
使用ET模式的epoll,需要将文件描述符设置为非阻塞,这个不是接口上的要求,是工程实践的要求。
假设这样的场景:服务器收到2k的请求,会向客户端返回一个应答数据。如果客户端收不到应答,不会发送第二个2k请求。
如果服务端写的代码是阻塞式的read,并且一次只read 1k的话(read不能保证一次就把所有的数据都读出来,可能被信号打断),剩下的9k的数据就会呆在缓冲区中。
此时由于epoll是ET模式,并不会认为文件描述符就绪。epoll_wait 就不会再次返回。剩下的9k会一直在缓冲区中。直到下一次客户端再给服务器写数据。epoll_wait才能返回。
问题来了:
- 服务器只读到1k数据,要10k读完才会给客户端返回响应数据。
- 客户端要读到服务器的响应,才会发送下一个请求。
- 客户端发送了下一个请求,epoll_wait 才会返回,才能去读缓冲区中剩余的数据。
所以,为了解决上述问题(阻塞read不一定能一下把完整的请求读完),于是就可以使用非阻塞轮询的方式来读缓冲区,保证一次能把完整的请求都读出来。
而如果是LT没这个问题,因为只要缓冲区中的数据没读完,就能够让epoll_wait返回文件描述符读就绪。
epoll的使用场景
epoll的高性能,是有一定的特定的场景的。如果场景选择的不适宜,epoll的性能可能会适得其反。
- 对于多链接,且多链接中只用一部分连接比较活跃时,比较适合使用epoll。
比如:一个需要处理上万个客户端的服务器,各种互联网APP的入口服务器,这样的服务器很适合epoll。但是如果只是系统内部,服务器和服务器间通信,只有少数的几个连接,这种情况下epoll就不合适。
epoll的惊群问题
该篇博客比较详细
ET模式的demo
源码地址
相关文章:

linux下高级IO模型
高级IO 1.高级IO模型基本概念1.1 阻塞IO1.2 非阻塞IO1.3 信号驱动IO1.4 IO多路转接1.5 异步IO 2. 模型代码实现2.1 非阻塞IO2.2 多路转接-selectselect函数介绍什么才叫就绪呢?demoselect特点 2.3 多路转接-pollpoll函数介绍poll优缺点demo 2.4 多路转接-epoll&…...

掌握Mojolicious会话管理:构建安全、持久的Web应用
掌握Mojolicious会话管理:构建安全、持久的Web应用 Mojolicious是一个基于Perl的高性能、异步Web开发框架,它提供了一套完整的工具来构建现代Web应用。会话管理是Web开发中的一个关键组成部分,它允许应用识别和保持用户的登录状态。本文将深…...

24西安电子科技大学马克思主义学院—考研录取情况
01、马克思主义学院各个方向 02、24马克思主义学院近三年复试分数线对比 PS:马院24年院线相对于23年院线增加15分,反映了大家对于马克思主义理论学习与研究的热情高涨,也彰显了学院在人才培养、学科建设及学术研究等方面的不断进步与成就。 6…...

12--RabbitMQ消息队列
前言:前面一章内容太多,写了kafka,这里就写一下同类产品rabbitmq,rabbitmq内容较少,正好用来过度一下,概念还是会用一些例子来说明,实际部署的内容会放在概念之后。 1、基础概念 1.1、MQ消息队…...

VMware替换关键技术:核心业务系统中,访存密集型应用的性能优化
越来越多用户采用虚拟化、超融合以及云平台环境来承载其核心业务,核心业务的高并发对性能的要求尤为严格,在VMware替换的热潮下,原VMware用户也更为关注新平台在核心业务上的性能表现是否对标,或实现超越。深信服将通过系列解析&a…...

[单master节点k8s部署]20.监控系统构建(五)Alertmanager
prometheus将监控到的异常事件发送给Alertmanager,然后Alertmanager将报警信息发送到邮箱等设备。可以从下图看出,push alerts是由Prometheus发起的。 安装Alertmanager config文件 [rootmaster prometheus]# cat alertmanager-cm.yaml kind: ConfigMa…...

用MySQL+node+vue做一个学生信息管理系统(四):制作增加、删除、修改的组件和对应的路由
1.下载依赖: npm install vue-router 在src目录下新建一个文件夹router,在router文件夹下新建一个文件router.js文件,在component目录下新建增加删除和修改的组件,引入router.js当中 此时的init组件为主页面((二、三&…...

磁盘就是一个超大的Byte数组,操作系统是如何管理的?
磁盘在操作系统的维度看,就是一个“超大的Byte数组”。 那么操作系统是如何对这块“超大的Byte数组”做管理的呢? 我们知道在逻辑上,上帝说是用“文件”的概念来进行管理的。于是,便有了“文件系统”。那么,文件系统…...

14-28 剑和诗人2 - 高性能编程Bend和Mojo
介绍: 在不断发展的计算世界中,软件和硬件之间的界限变得越来越模糊。随着我们不断突破技术可能性的界限,对能够利用现代硬件功能的高效、可扩展的编程语言的需求从未如此迫切。 Bend和 Mojo是编程语言领域的两种新秀,它们有望弥…...

Stable Diffusion:最全详细图解
Stable Diffusion,作为一种革命性的图像生成模型,自发布以来便因其卓越的生成质量和高效的计算性能而受到广泛关注。不同于以往的生成模型,Stable Diffusion在生成图像的过程中,采用了独特的扩散过程,结合深度学习技术…...

Apache Seata分布式事务之Seata-Client原理及流程详解
本文来自 Apache Seata官方文档,欢迎访问官网,查看更多深度文章。 本文来自 Apache Seata官方文档,欢迎访问官网,查看更多深度文章。 前言 在分布式系统中,分布式事务是一个必须要解决的问题,目前使用较多…...

Linux wget报未找到命令
wget报未找到命令需要安装wget 1、下载wget安装文件,本次于华为云资源镜像下载 地址:https://mirrors.huaweicloud.com/centos-vault/7.8.2003/os/x86_64/Packages/ 2、下载后上传到安装服务器/install_package,执行命令安装 rpm -ivh /i…...

38条Web测试经验分享
1. 页面链接检查 每一个链接是否都有对应的页面,并且页面之间切换正确。可以使用一些工具,如LinkBotPro、File-AIDCS、HTML Link Validater、Xenu等工具。 LinkBotPro不支持中文,中文字符显示为乱码;HTML Link Validater只能测…...

TCP报文校验和(checksum)计算
一. 原理 将TCP相关内容(TCP伪头部TCP头部TCP内容)转换成16比特的字符,然后进行累加,最后结果进行取反。TCP伪头部是固定的,下文有相关代码展示。 二. 源码 源码 #include <stdio.h> #include <stdlib.h&…...

【ue5】虚幻5同时开多个项目
正常开ue5项目我是直接在桌面点击快捷方式进入 只会打开一个项目 如果再想打开一个项目需要进入epic 再点击启动就可以再开一个项目了...
【Python实战因果推断】23_倾向分3
目录 Propensity Score Matching Inverse Propensity Weighting Propensity Score Matching 另一种控制倾向得分的常用方法是匹配估计法。这种方法搜索具有相似可观测特征的单位对,并比较接受干预与未接受干预的单位的结果。如果您有数据科学背景,您可…...

Qt源码解析之QObject
省去大部分virtual和public方法后,Qobject主要剩下以下成员: //qobject.h class Q_CORE_EXPORT Qobject{Q_OBJECTQ_PROPERTY(QString objectName READ objectName WRITE setObjectName NOTIFY objectNameChanged)Q_DECLARE_PRIVATE(QObject) public:Q_I…...

【算法专题】模拟算法题
模拟算法题往往不涉及复杂的数据结构或算法,而是侧重于对特定情景的代码实现,关键在于理解题目所描述的情境,并能够将其转化为代码逻辑。所以我们在处理这种类型的题目时,最好要现在演草纸上把情况理清楚,再动手编写代…...

分库分表真的适合你的系统吗?
曾几何时,“并发高就分库,数据大就分表”已经成了处理 MySQL 数据增长问题的圣经。 面试官喜欢问,博主喜欢写,候选人也喜欢背,似乎已经形成了一个闭环。 但你有没有思考过,分库分表真的适合你的系统吗&am…...

9 redis,memcached,nginx网络组件
课程目标: 1.网络模块要处理哪些事情 2.reactor是怎么处理这些事情的 3.reactor怎么封装 4.网络模块与业务逻辑的关系 5.怎么优化reactor? io函数 函数调用 都有两个作用:io检测 是否就绪 io操作 1. int clientfd = accept(listenfd, &addr, &len); 检测 全连接队列…...

【MySQL】事务四大特性以及实现原理
事务四大特性 原子性(Atomicity) 事务中的所有操作要么全部完成,要么全部不执行。如果事务中的任何一步失败,整个事务都会被回滚,以保持数据的完整性。 一致性(Consistency) 事务应确保数据库…...

【控制Android.bp的编译】
1.首先Android.bp的语法是不支持if 条件语句的 2.查到可以用enabled来控制Android.bp中的模块是否参与编译,但是并不能实现动态的控制,比如你需要根据获取到的安卓版本来控制一个Android.bp是否编译,是无法做到的。enabled只能是固定的true或…...

【车载开发系列】J-Link/JFlash 简介与驱动安装方法
【车载开发系列】J-Link/JFlash 简介与驱动安装方法 【车载开发系列】J-Link/JFlash 简介与驱动安装方法 【车载开发系列】J-Link/JFlash 简介与驱动安装方法一. 软件介绍二. 下载安装包二. 开始安装三. 确认安装四. J-Flash的使用 一. 软件介绍 J-Link是SEGGER公司为支持仿真…...

207 课程表
题目 你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1 。 在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] [ai, bi] ,表示如果要学习课程 ai 则 必须 先学习课程 bi 。 …...

罗剑锋的C++实战笔记学习(一):const、智能指针、lambda表达式
1、const 1)、常量 const一般的用法就是修饰变量、引用、指针,修饰之后它们就变成了常量,需要注意的是const并未区分出编译期常量和运行期常量,并且const只保证了运行时不直接被修改 一般的情况,const放在左边&…...

宁德时代天行发布,商用车超充时代来临
近日,宁德时代正式推出商用动力电池品牌——“宁德时代天行”,同时发布“宁德时代天行轻型商用车(L)-超充版”和“宁德时代天行轻型商用车(L)-长续航版”两款产品,可实现4C超充能力和500km的实况…...

硅纪元应用评测 | 弱智吧大战GPT4o和Claude 3.5 Sonnet
"硅纪元AI应用测评"栏目,深入解析和评测最新的人工智能应用,提供专业见解和实用建议。不论您是AI专家还是科技爱好者,都能找到权威、详尽的测评,帮助您在快速发展的AI领域中做出最佳选择。一起探索AI的真实潜力…...

注意力机制 attention Transformer 笔记
动手学深度学习 这里写自定义目录标题 注意力加性注意力缩放点积注意力多头注意力自注意力Transformer 注意力 注意力汇聚的输出为值的加权和 查询的长度为q,键的长度为k,值的长度为v。 q ∈ 1 q , k ∈ 1 k , v ∈ R 1 v {\bf{q}} \in {^{1 \times…...

开始尝试从0写一个项目--后端(二)
实现学生管理 新增学生 接口设计 请求路径:/admin/student 请求方法:POST 请求参数:请求头:Headers:"Content-Type": "application/json" 请求体:Body: id 学生id …...

【图解大数据技术】Hive、HBase
【图解大数据技术】Hive、HBase Hive数据仓库Hive的执行流程Hive架构数据导入Hive HBaseHBase简介HBase架构HBase的列式存储HBase建表流程HBase数据写入流程HBase数据读取流程 Hive Hive是基于Hadoop的一个数据仓库工具,Hive的数据存储在HDFS上,底层基于…...