根据源码,模拟实现 RabbitMQ - 从需求分析到实现核心类(1)
目录
一、需求分析
1.1、对 Message Queue 的认识
1.2、消息队列核心概念
1.3、Broker Server 内部关键概念
1.4、Broker Server 核心 API (重点实现)
1.5、交换机类型
Direct 直接交换机
Fanout 扇出交换机
Topic 主题交换机
1.6、持久化
1.7、网络通信
通信流程
远程调用设计思想
1.8、模块设计图
二、实现核心类
2.1、交换机和队列的属性及绑定关系
2.2、Message 消息
一、需求分析
1.1、对 Message Queue 的认识
消息队列就是把 阻塞队列 这样的数据结构,单独提取成了一个独立的程序进行部署,实现 “进程和进程之间 / 服务和服务之间” 的生产者消费者模型(分布式系统中则是一组服务器构成的集群).
生产者消费者模型的好处如下:
- 解耦合:在一个分布式系统中 服务器A 给 服务器B 发送请求,B 给 A 返回响应,这样 A 和 B 的耦合是比较大的(B 一旦挂了,A 这边也无法正常接收响应);引入消息队列后,A 把请求发送给消息队列,B 再从消息队列中获取请求,就降低了耦合度(哪怕 B 挂了,A 也不用管,继续发送请求给消息队列,队列反馈响应).
- 削峰填谷:假设这样一个常见, A 是入口服务器, A 再调用 B 完成一些具体的业务,如果是 A 和 B 直接通信,突然有一天 A 收到用户请求的峰值,此时 B 也会随之感受到峰值;引入消息队列之后, A 把请求发给队列,这时候 B 就可以按照自己原有的节奏从队列中取请求,不至于一下子收到太多的并发量.
1.2、消息队列核心概念
生产者(Producer):发布消息的客户端应用程序.
消费者(Consumer):订阅消息的客户端应用程序,用于处理生产者产生的消息.
中间人(Broker):消费者要拿到生产者的消息,需要经过中间人,用来削峰填谷.
发布(Publish):生产者向中间人这里投递消息的过程.
订阅(Subscribe):类似于订阅报纸,消费者要从中间人这里取到对应消息的前提是,先订阅消息.
消费(Consume):消费者从中间人这里取数据的操作.
1.3、Broker Server 内部关键概念
1.虚拟主机(Virtual Host):类似于 MySQL 中的 database,是一个 “逻辑” 上的数据集合.
实际的开发中,一个 Broker Server 也可以有多种不同类型的数据,可能会同时用来管理多组 业务线 上的数据,可以使用 Virtual Host 进行逻辑上的区分~
2.交换机(Exchange):实际上,生产者是先把消息给了 Broker Server 上的某一个交换机,再由交换机把消息转发给对应的队列.
交换机就类似于公司的前台小姐姐,有一天你来面试,你就告诉前台小姐姐,然后她就会把你带到对应的楼层(队列).
3.队列(Queue):在一个大的消息队列中,可以又很多哥具体的小队列,他们用来存储消息实体,后续消费者也是从对应的队列中取数据.
4.绑定(Binding):把交换机和队列之间,建立起关联关系.
可以把 交换机 和 队列 看作 数据库 中的 “多对多” 这样的关系.
5.消息(Message):服务器 A 给 B 发的请求(通过 MQ 转发),就是一个消息,服务器 B 给 A 返回的响应(通过 MQ 转发)也是一个消息.
一个消息,可以视为是一个 字符串(二进制数据)。消息中具体包含啥样的数据,都是程序员自定义的.
Ps:这些概念,既需要在内存中存储(方便,快),也需要在硬盘中存储(持久化).
1.4、Broker Server 核心 API (重点实现)
1. 创建队列(queueDeclare)
这里不使用 Create 创建 这样的术语,而使用 Declare ,是因为这里以 RabbitMQ 为蓝本, Declare 表示 不存在则创建,存在就什么也不干.
2.销毁队列(queueDelete)
3.创建交换机(exchangeDeclare)
4.销毁交换机(exchangeDelete)
5.创建绑定(queueBind)
6.解除绑定(queueUnbind)
7.发布消息(basicPublish)
8.订阅消息(basicConsume)
9.确定消息(basicAck)
类似于 TCP 的确认应答机制,确认消息这个 api 就是让消费者显式告诉 broker server ,这个消息,我已经处理完毕了,提高整个系统的可靠性.
客户端除了提供以上 9 中方法,还需要提供 4 个方法:
1.创建 Connection
2.关闭 Connection
3.创建 Channel
4.关闭 Channel
一个 Connection 对象,就代表一个 TCP 连接,里面可以包含多个 Channel ,每隔 Channel 上面传输的数据都是互不相干的.
有了 Connection 了,为什么还要搞一个 Channel ?
TCP 中,建立 / 断开一个连接成本还是挺高的,因此,很多时候,不希望频繁的建立断开 TCP 连接,因此引入 Channel ,相比于 TCP,就要轻量很多. Connection 和 Channel 之间的关系,就类似于 “网线” 一样.
1.5、交换机类型
交换机在转发消息的时候,按照转发规则,提供了几种不同的 交换机类型(ExchangeType)来描述这里不同的转发规则.
RabbitMQ 主要实现了 四种 交换机类型(也是 AMQP 协议定义的)
- Direct 直接交换机
- Fanout 扇出交换机
- Topic 主题交换机
- Header 消息头交换机
Ps:这里主要实现前三种交换机类型,因为第四种交换机规则复杂,应用场景少,前三种就已经够用了.
Direct 直接交换机
有两个关键概念:
bindingKey:把队列和交换机绑定的时候,指定一个单词(类似于暗号).
routingKey:生产者发送消息的时候,也指定一个单词.
当 routingKey 和 BindingKey 对上暗号了,就可以把这个消息转发到对应的队列中了.
生产者发送消息的时候,会指定一个 “目标队列的名字”(routingKey),交换机收到之后,就看看绑定的队列里,有没有匹配的队列(BindingKey),如果有,就转发过去(把消息塞进对应的队列中),如果没有,消息直接丢弃.
Fanout 扇出交换机
会将接收到的消息广播到每一个跟其绑定的queue,最后交给对应的消费者,值得注意的是,exchange负责消息路由,而不是存储,路由失败则消息丢失。
Topic 主题交换机
有两个关键概念:
bindingKey:把队列和交换机绑定的时候,指定一个单词(类似于暗号).
routingKey:生产者发送消息的时候,也指定一个单词.
当 routingKey 和 BindingKey 对上暗号了,就可以把这个消息转发到对应的队列中了.
Ps:TopicExchange 与 DirectExchange 十分类似,区别在于routingKey必须是多个单词的列表,并且以 . 分割。
1.6、持久化
上述这些概念(交换机、队列、绑定、消息....)对应的数据,都需要存储和管理起来,此时内存和硬盘都会各自存储一份,内存为主,硬盘为辅.
在内存中存储的原因:对于 MQ 来说,能够高效的转发处理数据式非常关键的,因此在内存上组织数据比硬盘上要快的多.
在硬盘上存储的原因:防止内存中的数据随着 进程重启/主机重启 而丢失.
Ps:硬盘存储,这个持久化是相对于 内存 的,对于一个硬盘来说,存储的消息寿命一般为 几年~几十年(一直不通电的情况下).
1.7、网络通信
通信流程
⽣产者和消费者都是客⼾端程序, broker server 则是作为服务器. 通过⽹络进⾏通信.
例如如下过程:
- 客户端发送请求:生产者的代码中需要有一个方法 queueDeclare 来创建队列,这个方法内部要做的事情就是给服务器发送一个请求,告诉服务器,咱们要创建一个队列,以及队列长啥样子......
- 服务器处理请求,并返回响应:broker server 收到这个请求之后,再执行服务器这边的 queueDeclare 方法,真正取给 内存/硬盘 上写一些数据,把这个队列给真正创建出来,再把创建 成功/失败 结果包装成响应,返回给客户端.
- 客户端接收响应:当响应回来了,客户端的 queueDeclare 就会获取到这个响应,看到 创建队列成功,此时 queueDeclare 就算执行完毕了.
远程调用设计思想
此处,客户端调用了一个本地方法,结果这个方法的背后,又给服务器发送了一系列消息,由服务器完成了一系列工作,站在调用者的角度,只是看到了这个功能完成了,并不知道背后的实现细节.
虽然调用的是一个本地方法,但实际上好像调用另一个远端服务器的方法一样~
这里可以认为是编写客户端服务器程序,通信过程中的一种设计思想——远程调用(RPC)
举个例子
以前有个美国的老哥,再大厂干活,但是他特别想摸鱼,于是他就找了一个中国人帮他干(有偿). 同样级别的程序员,在美国工作的薪水是国内的 3-4 倍.
1.8、模块设计图
二、实现核心类
Ps:Spring boot、MyBatis
2.1、交换机和队列的属性及绑定关系
我们可以使用 一个枚举类 表示三种交换机.
public enum ExchangeType {DIRECT(0),FANOUT(1),TOPIC(2);private final int type;private ExchangeType(int type) {this.type = type;}public int getType() {return type;}}
交换机属性如下
public class Exchange {//模仿 rabbitmq 使用 name 作为唯一身份标识private String name;//交换价类型,DIRECT,FANOUT,TOPICprivate ExchangeType type = ExchangeType.DIRECT;//当前交换机是否要持久化存储,true 标识持久化.private boolean durable = false;//TODO: 若当前交换机没人使用了,就会自动删除private boolean autoDelete = false;//TODO: 表示创建交换机时可以指定一些额外的选项private Map<String, Object> arguments = new HashMap<>();public String getName() {return name;}public void setName(String name) {this.name = name;}public ExchangeType getType() {return type;}public void setType(ExchangeType type) {this.type = type;}public boolean isDurable() {return durable;}public void setDurable(boolean durable) {this.durable = durable;}public boolean isAutoDelete() {return autoDelete;}public void setAutoDelete(boolean autoDelete) {this.autoDelete = autoDelete;}public Map<String, Object> getArguments() {return arguments;}public void setArguments(Map<String, Object> arguments) {this.arguments = arguments;}
}
队列属性如下
public class MSGQueue {//表示队列的身份标识private String name;//是否持久化,true 表示支持private boolean durable;//TODO: 这个属性为 true,表示队列只能被一个消费者使用, false表示大家都能用private boolean exclusive = false;//TODO: 自动删除,为 true 表示没有人使用以后自动删除private boolean autoDelete = false;//TODO: 扩展参数,自定义选项private Map<String, Object> arguments = new HashMap<>();public String getName() {return name;}public void setName(String name) {this.name = name;}public boolean isDurable() {return durable;}public void setDurable(boolean durable) {this.durable = durable;}public boolean isExclusive() {return exclusive;}public void setExclusive(boolean exclusive) {this.exclusive = exclusive;}public boolean isAutoDelete() {return autoDelete;}public void setAutoDelete(boolean autoDelete) {this.autoDelete = autoDelete;}public Map<String, Object> getArguments() {return arguments;}public void setArguments(Map<String, Object> arguments) {this.arguments = arguments;}
}
交换机和队列绑定关系如下
public class Binding {//交换机身份标识private String exchangeName;//队列身份标识private String queueName;private String bindingKey;//绑定没必要设置持久化,因为没有意义,他存在的意义前提是 交换机和队列存在(持久化)public String getExchangeName() {return exchangeName;}public void setExchangeName(String exchangeName) {this.exchangeName = exchangeName;}public String getQueueName() {return queueName;}public void setQueueName(String queueName) {this.queueName = queueName;}public String getBindingKey() {return bindingKey;}public void setBindingKey(String bindingKey) {this.bindingKey = bindingKey;}
}
2.2、Message 消息
Message 消息主要分为:
- 属性部分 BasicProperties(网络):这是一个自定义类,里面承载着 Message 核心属性,如 消息的唯一身份标识、routingKey、是否需要持久化.......
- 正文部分 byte[]:承载着具体的消息内容.
- 辅助属性:通过 offsetBeg 和 offsetEnd 快速找到文件中某一个消息的具体位置(一个文件中会存储很多消息),这里约定的规则为 “前闭后开”(以字节为单位);isValid 标识消息要删除,如果删除采用逻辑删除(并不是真的删除,而是标记为无效数据),这里约定 0x1 为有效数据、0x0 表示无效数据.
Ps:前两个信息需要在网络上传输,并且写入文件,因此就需要通过 Serializable 序列化和反序列化(直接继承接口即可,不需要具体实现)~~
而第三条不需要被序列化保存到文件中,这个属性主要是为了内存中的 Message 对象快速找到 文件中的 Message 对象,因此使用 trasient 修饰即可防止序列化
public class Message implements Serializable {//这两个属性是 Message 最核心的属性private BasicProperties basicProperties = new BasicProperties();private byte[] body;//以下是辅助类型的属性private transient long offsetBeg = 0; //消息数据的开头距离文件开头的位置偏移量(字节)private transient long offsetEnd = 0; //消息数据的结尾距离文件开头的位置偏移量(字节)//表示文件中的消息是否是有效消息(对文件中的消息,如果删除,使用逻辑删除)// 0x1 表示有效, 0x0 表示无效private byte isValid = 0x1;//创建一个工厂方法,让工厂方法创建 Message 对象//此方法中创建的 Message 对象,会自动生成唯一的 MessageId//万一 routingKey 和 basicProperties 里的 routingKey 冲突,以外面为主public static Message createMessageWithId(String routingKey, BasicProperties basicProperties, byte[] body) {Message message = new Message();if(basicProperties != null) {message.setBasicProperties(basicProperties);}//生成的 MessageId 以 M- 作为前缀message.setMessageId("M-" + UUID.randomUUID());message.setRoutingKey(routingKey);message.body = body;// offsetBeg, offsetEnd, isValid ,是消息持久化的时候才会用到,消息写入文件之前在进行设定return message;}public String getMessageId() {return basicProperties.getMessageId();}public void setMessageId(String messageId) {basicProperties.setMessageId(messageId);}public String getRoutingKey() {return basicProperties.getRoutingKey();}public void setRoutingKey(String routingKey) {basicProperties.setRoutingKey(routingKey);}public int getDeliverMode() {return basicProperties.getDeliverMode();}public void setDeliverMode(int mode) {basicProperties.setDeliverMode(mode);}public BasicProperties getBasicProperties() {return basicProperties;}public void setBasicProperties(BasicProperties basicProperties) {this.basicProperties = basicProperties;}public byte[] getBody() {return body;}public void setBody(byte[] body) {this.body = body;}public long getOffsetBeg() {return offsetBeg;}public void setOffsetBeg(long offsetBeg) {this.offsetBeg = offsetBeg;}public long getOffsetEnd() {return offsetEnd;}public void setOffsetEnd(long offsetEnd) {this.offsetEnd = offsetEnd;}public byte getIsValid() {return isValid;}public void setIsValid(byte isValid) {this.isValid = isValid;}
}
Message 中的核心属性如下
public class BasicProperties implements Serializable {//消息的唯一标识(使用 UUID 保证唯一性)private String messageId;//和 bindingKey 做匹配//如果当前交换机类型是 DIRECT ,此时 routingKey 就表示要转发的队列名//如果当前交换机类型是 FANOUT ,此时 routingKey 无意义(不使用)//如果当前交换机类型是 TOPIC ,此时 routingKey 就是要和 bindingKey 做匹配,匹配才进行转发private String routingKey;//标识消息是否要持久化,1 表示不持久化, 2 表示持久化(rabbitmq 是这么搞得)private int deliverMode = 1;//RabbitMQ 还有其他属性,这里就不考虑了public String getMessageId() {return messageId;}public void setMessageId(String messageId) {this.messageId = messageId;}public String getRoutingKey() {return routingKey;}public void setRoutingKey(String routingKey) {this.routingKey = routingKey;}public int getDeliverMode() {return deliverMode;}public void setDeliverMode(int deliverMode) {this.deliverMode = deliverMode;}
}
相关文章:

根据源码,模拟实现 RabbitMQ - 从需求分析到实现核心类(1)
目录 一、需求分析 1.1、对 Message Queue 的认识 1.2、消息队列核心概念 1.3、Broker Server 内部关键概念 1.4、Broker Server 核心 API (重点实现) 1.5、交换机类型 Direct 直接交换机 Fanout 扇出交换机 Topic 主题交换机 1.6、持久化 1.7…...

企业服务器数据库遭到malox勒索病毒攻击后如何解决,勒索病毒解密
网络技术的发展不仅为企业带来了更高的效率,还为企业带来信息安全威胁,其中较为常见的就是勒索病毒攻击。近期,我们公司收到很多企业的求助,企业的服务器数据库遭到了malox勒索病毒攻击,导致系统内部的许多重要数据被加…...

udp与can通信的选择与比较
UDP(用户数据报协议)和CAN(控制器局域网)是两种不同的通信协议,它们在实时传递性上有一些区别。 UDP是一种无连接的传输协议,它提供了简单的、不可靠的数据传输。UDP不提供可靠性保证、流控制或重传机制。…...

HoudiniVex笔记_P24_ForceBasics力基础
原视频:https://www.youtube.com/playlist?listPLzRzqTjuGIDhiXsP0hN3qBxAZ6lkVfGDI Bili:Houdini最强VEX算法教程 - VEX for Algorithmic Design_哔哩哔哩_bilibili Houdini版本:19.5 1、什么是Force 本章主要讲重力、弹力、速度与质量、…...

半导体退火那些事(1)
1.半导体退火的原理 半导体材料在晶体生长和制造过程中,由于各种原因会出现缺陷、杂质、位错等结构性缺陷,导致晶格不完整,施加电场后的电导率较低。通过退火处理,可以使材料得到修复,结晶体内部重新排列,…...

MapReduce介绍
目录 一、什么是MapReduce 二、MapReduce 的设计思想 2.1 分而治之 2.2 构建抽象模型:Map和Reduce 2.3 隐藏系统层细节 三、MapReduce 的框架原理 3.1 MRv1工作原理 3.1.1 MRv1架构工作原理图 3.1.1.1 流程说明 3.1.1.1.1 作业的提交 3.1.1.1.2 作业的初始化 3…...
Redis支持的主要数据结构操作命令有哪些?
Redis支持多种数据结构操作命令,包括以下主要命令: 字符串(Strings): SET:设置字符串键的值。GET:获取指定键的值。INCR/DECR:对存储整数的字符串执行加一或减一操作。APPEND&#x…...

环境与能源创新专题:地级市绿色创新、碳排放与环境规制数据
数据简介:推动绿色发展,促进人与自然和谐共生是重大战略举措。绿色发展强调“绿水青山就是金山银山”,人与自然和谐共生重在正确处理生态环境保护与经济发展的关系。在着力于实现绿色发展的过程中,绿色创新是绿色发展的重要驱动因…...

设计模式之门面模式(Facade)的C++实现
1、门面模式提出 在组件的开发过程中,某些接口之间的依赖是比较紧密的,如果某个接口发生变化,其他的接口也会跟着发生变化,这样的代码违背了代码的设计原则。门面设计模式是在外部客户程序和系统程序之间添加了一层中间接口&…...

【数理知识】向量与基的内积,Matlab 代码验证
序号内容1【数理知识】向量的坐标基表示法,Matlab 代码验证2【数理知识】向量与基的内积,Matlab 代码验证 文章目录 1. 向量与基的内积2. 二维平面向量举例3. 代码验证Ref 1. 向量与基的内积 假设存在一个二维平面内的向量 a ⃗ \vec{a} a ,…...

黑客入侵:福特汽车Sync3车机存在漏洞,黑客入侵可抹除系统数据
据福特汽车公告,他们发现部分2021年至2022年车型的Sync3车机存在Wi-Fi漏洞,该漏洞可能被黑客利用来入侵并抹除车机内的系统数据。这一漏洞源于福特车系中采用的WL18xx MCP驱动程序的内存缓冲区溢位漏洞,其漏洞编号为CVE-2023-29468。 这一发现…...

面试热题(单词搜索)
给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相…...

自定义表格组件:实现表格中有固定列的功能逻辑
目录 1,效果图2,实现思路3,实现方式 1,效果图 可以拖动纵向滑块,最左边一列固定住。 以同样的道理,可以在右面固定一列 2,实现思路 作为一个table组件,要接受父组件中的对table的…...

uni-app弹窗列表滚动, 弹框下面的内容也跟随滚动解决方案
滑动弹窗里的列表,弹框下面的内容也会跟着滑动,导致弹窗中的列表不能正常滚动 1.弹窗组件代码,需要在最外层的view中加入touchmove.stop.prevent"moveHandle",且弹窗中需要滚动的列表要使用scroll-view标签包裹起来&…...
Django操作cookie、Django操作session、Django中的Session配置、CBV添加装饰器、中间件、csrf跨站请求
一、Django操作cookie cookie的原理cookie的工作原理是:由服务器产生内容,浏览器收到请求后保存在本地;当浏览器再次访问时,浏览器会自动带上Cookie,这样服务器就能通过Cookie的内容来判断这个是“谁”了。1.设置cook…...

内网穿透——使用Windows自带的网站程序建立网站
文章目录 1.前言2.Windows网页设置2.1 Windows IIS功能设置2.2 IIS网页访问测试 3. Cpolar内网穿透3.1 下载安装Cpolar3.2 Cpolar云端设置3.3 Cpolar本地设置 4.公网访问测试5.结语 1.前言 在网上各种教程和介绍中,搭建网页都会借助各种软件的帮助,比如…...

JavaScript请求数据的4种方法总结(Ajax、fetch、jQuery、axios)
JavaScript请求数据有4种主流方式,分别是Ajax、fetch、jQuery和axios。 一、Ajax、fetch、jQuery和axios的详细解释: 1、 Ajax Ajax(Asynchronous JavaScript and XML)是一种使用JavaScript在用户的浏览器上发送请求的技术&…...
js中的break和continue中的区别
js中break和continue有着一些差别。 首先,虽然break和continue都有跳出循环的作用,但break是完全跳出循环,而continue则是跳出一次循环,然后开启下一次的循环。 下面我就来举几个例子吧。 var num 0;for(var i 1;i < 10;i){i…...

Cat(2):下载与安装
1 github源码下载 要安装CAT,首先需要从github上下载最新版本的源码。 官方给出的建议如下: 注意cat的3.0代码分支更新都发布在master上,包括最新文档也都是这个分支注意文档请用最新master里面的代码文档作为标准,一些开源网站…...
程序崩溃生成dump文件定位到崩溃处
#include <DbgHelp.h> #pragma comment(lib,"Dbghelp.lib")long __stdcall CrashInfocallback(_EXCEPTION_POINTERS* pexcp) {// 创建dmp文件HANDLE hDumpFile ::CreateFile(L"Memory.DMP",GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORM…...
React 第五十五节 Router 中 useAsyncError的使用详解
前言 useAsyncError 是 React Router v6.4 引入的一个钩子,用于处理异步操作(如数据加载)中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误:捕获在 loader 或 action 中发生的异步错误替…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...
Java - Mysql数据类型对应
Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...

SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...

用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...
全面解析数据库:从基础概念到前沿应用
在数字化时代,数据已成为企业和社会发展的核心资产,而数据库作为存储、管理和处理数据的关键工具,在各个领域发挥着举足轻重的作用。从电商平台的商品信息管理,到社交网络的用户数据存储,再到金融行业的交易记录处理&a…...