RabbitMQ 消息传递

news2024/11/24 1:52:51

消息何去何从

mandatoryimmediate是channel.basicPublish方法中的两个参数,他们都有当消息传递过程中不可达目的地时将消息返回给生产者的功能。RabbitMQ提供的备份交换器可以将未能被交换器路由的消息(没有绑定队列或者没有匹配的绑定)存储起来,而不用返回给客户端。

mandatory参数

当mandatory参数为true时,交换器无法根据自身的类型和路由键找到符合条件的队列,那么RabbitMQ会调用Basic.Return命令将消息返回给生产者。当参数为false时,出现上述情形,则消息直接丢弃。

生产者通过调用channel.addReturnListener来添加ReturnListener监听器实现。

代码示例:
在这里插入图片描述
从AMQP协议层面来说,其对应的流转过程如下
在这里插入图片描述

immediate参数(已弃用)

当immediate参数为true时,如果交换器在将消息路由到队列时发现队列上并不存在任何消费者,那么这条消息不会存入队列中。当与路由键匹配的所有队列都没有消费者时,该消息会通过Basic.Return返回生产者。

总结

mandatory参数:告诉服务器至少将该消息路由到一个队列中,否则将消息返回给生产者。

immediate参数:告诉服务器,如果该消息关联的队列上有消费者,则立刻投递;如果所有匹配的队列上都没有消费者,则直接将消息返还给生产者,不用将消息存入队列等待消费者了。

备份交换器(AE)

生产者在发送消息的时候如果不设置mandatory参数,那么消息在未被路由器的情况下将会丢失;如果设置了mandatory参数,那么需要添加ReturnListener的编程逻辑,生产者代码将会变得复杂。使用 备份交换器,可以将未被路由的消息存储在RabbitMQ中,再在需要的时候去处理这些消息

声明备份交换器的方式:
在这里插入图片描述在这里插入图片描述
上面的代码中声明了两个交换器normalExchange和myAe,分别绑定了normalQueue和unroutedQueue。同时,将myAe设置为normalExchange的备份交换器。注意,myAe的交换器类型为fanout

如果此时发送一条消息到normalExchange上,当路由键等于“normalKey”的时候,消息能正确路由到normalQueue这个队列中,如果路由键设为其他值,比如“errorKey”,即消息不能被正确的路由到normalExchange绑定的任何队列上,此时就会发送给myAe,进而发送到unroutedQueue这个队列。

在这里插入图片描述
注意以下几种情况:

  • 如果设置的备份交换器不存在,客户端和服务端都不会有异常,此时消息会丢失。
  • 如果备份交换器没有绑定任何队列,客户端和服务端都不会有异常,此时消息会丢失。
  • 如果备份交换器没有任何匹配的队列,客户端和服务端都不会有异常,此时消息会丢失。
  • 如果备份交换器和mandatory参数一起使用,那么mandatory参数无效。

消息过期时间(TTL)

TTL,过期时间,RabbitMQ可以对消息和队列设置过期时间。

设置消息的TTL

设置消息的TTL有两种方法,如果两种方法一起使用,则消息的TTL以两者之间较小的那个数值为准。

    1. 通过队列属性设置:队列中所有消息都有相同的过期时间。
    1. 对消息本身进行单独设置:每条消息的过期时间都不同。

消息在队列中的生存时间一旦超过设置的TTL时,就会变成 “死信” ,消费者将无法再收到该消息。

1. 通过队列属性设置消息TTL
在channel.queueDeclare方法中加入x-message-ttl参数实现,参数单位是毫秒。
在这里插入图片描述
如果不设置TTL,表示消息不会过期,如果TTL设置为0,表示除非此时可以直接将消息投递到消费者,否则该消息会被立即丢弃。

2. 设置单条消息的TTL
在channel.basicPublish方法中加入expiration属性,单位是ms。
在这里插入图片描述
对于设置队列属性的消息,一旦过期,就会从队列中抹去。而第二种方法,即使消息过期,也不会马上从队列中抹去,因为这条消息是否过期是在即将投递到消费者之前判定的。

设置队列的TTL

设置队列的TTL,可以控制队列被自动删除前处于未使用状态的时间。未使用表明该队列上没有任何的消费者,队列也没有被重新声明,并且在过期时间段内也未调用过Basic.Get命令。

RabbitMQ会确保在过期时间到达后将队列删除,但是不保证删除的动作有多及时,在MQ重启后,持久化队列的过期时间会被重新计算。

示例代码:

Map<String,Object> args = new HashMap<>();
args.put("x-expires",180000); //单位ms
channel.queueDeclare("myqueue",false,false,false,args);

三种特殊消息队列

1. 死信队列

DLX,死信交换机,也称为死信邮箱。当消息在一个队列中变成死信之后,他能被重新发送到另一个交换器中,这个交换器就是DLX。绑定DLX的队列称为死信队列。

消息变成死信一般由于以下几种情况:

  • 消息者拒绝消费,并且设置requeue参数为false。
  • 消息过期
  • 队列到达最大长度。

死信队列,实际上就是设置某个队列的属性。当这个队列中存在死信时,MQ就会自动的将这个消息重新发布到设置的DLX上去,进而被路由到另一个队列,即死信队列。可以监听这个队列中的消息已进行相应的处理。这个特性与将该消息的TTL设置为0配合使用可以弥补immedaite参数的功能。

声明死信队列的方式

通过在channel.queueDeclare方法中设置x-dead-letter-exchange参数来为这个队列添加DLX。

channel.exchangeDeclare("dlx-exchange","direct");
Map<String,Object> args = new HashMap<>();
args.put("x-dead-letter-exchange","dlx_exchange");
//为队列添加DLX
channel.queueDeclare("myqueue",false,false,false,args);

创建队列,并且为其设置TTL和DLX

channel.exchangeDeclare("exchange.dlx","direct",true);
channel.exchangeDeclare("exchange.normal","fanout",true);
Map<String,Object> args = new HashMap<>();
args.put("x-message-ttl",10000);
args.put("x-dead-letter-exchange","exchange.dlx");
args.put("x-dead-letter-routing-key","routingKey");
channel.queueDeclare("queue.normal",true,false,false,args);
channel.queueBind("queue.normal","exchange.normal","");
channel.queueBind("queue.normal","exchange.normal","");
channel.queueDeclare("queue.dlx",true,false,false,null);
channel.queueBind("queue.dlx","exchange.dlx","routingKey");
channel.basicPublish("exchange.normal","rk",MessageProperties.PERSISTENT_TEXT_PLAIN,"dlx".getBytes());

消息路由过程
在这里插入图片描述
生产者首先发送一条携带路由键为“rk”的消息,然后经过交换器exchange.normal顺利的存储到队列queue.normal中。由于队列queue.normal设置了过期时间为10s。在这10s内没有消费者消费这条消息,那么判定这条消息为过期。由于设置了DLX,过期之时,消息被丢弃给交换器exchange.dlx中,这时找到与exchange.dlx匹配的队列queue.dlx,最后消息被存储在queue.dlx这个死信队列中。

2. 延迟队列

延迟队列的使用场景有很多,比如:

  • 在订单系统中,一个用户下单后通常有30分钟的时间进行支付,如果在30分钟内没有支付成功,那么这个订单将进行异常处理,这时就可以使用延迟队列来处理这些订单。
  • 用户系统通过手机远程遥控家里的智能设备在指定的时间进行工作,这时候就可以将用户指令发送到延迟队列,当指令设定的时间到了再将指令推送到智能设备。

在AMQP协议中,本身没有直接支持延迟队列的功能,但是可以通过前面的DLX和TTL模拟出延迟队列的功能。

在这里插入图片描述
在真实应用中,对于延迟队列可以根据延迟时间的长短分为多个等级,一般分为5s、10s、30s、1分钟、5分钟、10分钟、30分钟、1小时等维度。

如图所示,根据应用需求的不同,生产者在发送消息的时候通过设置不同的路由键,将消息发送到与交换器绑定的不同队列中,这里队列分别设置了时间为5s、10s、30s、1分钟,同时也分别设置了DLX和相应的死信队列。

当消息过期时,就会转存到相应的死信队列(即延迟队列中),这样消费者根据业务自身情况,分别选择不同延迟等级的延迟队列进行消费。

3. 优先级队列

优先级高的消息具备优先被消费的特权。

可以通过设置队列的x-max-priority参数来实现

Map<String,Object> args = new HashMap<>();
args.put("x-max-priority",10);
channel.queueDeclare("queue.priority",true,false,false,args);

上述代码演示如何配置一个队列的最大优先级,再此之后,需要在发送时在消息中设置消息当前的优先级。
在这里插入图片描述
代码中设置消息优先级为5,默认最低为0,最高为队列设置的最大优先级。优先级高的消息可以被优先消费,如果消费者的消费速度大于生产者的速度且Broker中没有消息堆积的情况下,对发送的消息设置优先级就没有什么实际意义。

使用消息队列实现RPC

RPC即远程过程调用,他的主要功用是让构建分布式计算更容易。一般在RabbitMQ中进行RPC是很简单的,客户端发送请求消息,服务端回复响应消息。为了接收响应的消息,我们需要在请求消息中发送一个回调队列,如下所示。

设置回调队列
在这里插入图片描述
在BasicProperties中,包含了14个属性,这里用到其中两个属性

  • replyTo: 通常用来设置一个回调队列
  • correlationId:用来关联请求和其调用RPC之后的回复。

使用上述代码,为每个RPC请求创建一个回调队列,是非常低效的,我们可以使用一个更具通用性的方案,为每个客户端创建一个单一的回调队列。

这样就产生了一个新的问题,对于回调队列而言,在其接收到一条回复的消息之后,他并不知道这条消息应该和哪个请求匹配。这里就用到了correlationId,为每一个请求设置一个唯一的correlationId。之后,在回调队列接收到回复的消息时,可以根据这个属性匹配到响应的请求。如果收到一个未知的correlationId,则可以简单的将其丢弃。

在这里插入图片描述
RPC处理流程

  • 当客户端启动时,创建一个匿名的回调队列
  • 客户端为RPC请求设置2个属性,replyTo用来告知RPC服务端回复请求时的目的队列即回调队列,correlationId用来标记一个请求。
  • 请求被发送到rpc_queue队列中。
  • RPC服务端监听rpc_queue队列中的请求,当请求到来时,服务端会处理并且把带有结果的消息发送给客户端,接受的队列就是replyTo设定的回调队列。
  • 客户端监听回调队列,当有消息时,检查correlationId属性,如果与请求匹配,那就是结果了。

示例代码

RPC服务端代码
在这里插入图片描述
在这里插入图片描述
RPC客户端代码

在这里插入图片描述
在这里插入图片描述

持久化

RabbitMQ的持久化分为三个部分:交换器的持久化、队列的持久化、消息的持久化

交换器的持久化是通过在声明交换器时将durable参数设置为true实现。如果交换器不设置持久化,那么在MQ服务重启后,相关的 交换器元数据会丢失。不过消息不会丢失,只是不能将消息发送到这个交换器了。对于一个长期使用的交换器来说,需要设置为持久化

队列的持久化是通过在声明队列时将durable参数设置为true实现,如果队列不设置持久化,那么在MQ服务器重启之后,相关队列的元数据会丢失,数据也会丢失。设置了队列的持久化可以保证其本身元数据不会因为异常而丢失,但是并不能保证内部所存储的消息不会丢失。为了确保消息不丢失,需要设置消息的投递模式(deliveryMode)为2。前面实例中的MessageProperties.PERSISTENT_TEXT_PALIN实际上是封装了这个属性。
在这里插入图片描述
注意

  1. 设置队列和消息持久化,当MQ服务重启之后,消息依旧存在。单单只设置队列持久化,重启之后消息会丢失;单单只设置消息持久化,重启之后队列丢失,继而消息也会丢失。

  2. 可以将所有的消息都设置为持久化,但是这样会严重影响MQ的性能。写入磁盘的速度比写入内存速度慢得多。在选择是否要持久化消息时,需要在可靠性和吞吐量之间做一个权衡。

将交换器、队列、消息都设置持久化之后,能保证百分百不丢失数据吗,答案是否定的,有如下几种场景。

第一种:消费者设置autoAck为true时,那么消费者接收到消息之后,还没来得及处理就宕机了。

第二种:在持久化的消息正确存入MQ之后,还需要一段时间才能存入磁盘。MQ并不会为每条消息都进行同步存盘(调用内核的fsync方法)处理,可能仅仅保存到操作系统缓存之中而不是物理磁盘之中。如果这段时间内MQ发生宕机,消息还未来得及落盘。可以使用MQ镜像队列机制或者发送方确认机制来解决。

如何保证消息不丢失

生产者确认

在使用MQ的时候,可以通过持久化操作来解决因为服务器异常崩溃而导致的消息丢失,除此之外,当消息的生产者将消息发送出去之后,消息到底有没有正确到达服务器?如果不进行特殊配置,默认情况下发送出去的消息没有任何返回的信息给生产者。如果在消息达到服务器之前丢失,持久化操作解决不了问题

RabbitMQ针对这个问题,提供了两种解决方式:

  • 通过事务机制实现
  • 通过发送方确认机制实现。
事务机制

channel.txSelect : 用于将信道设置成事务模式。
channel.txCommit : 用于提交事务。
channel.txRollback: 用于事务回滚。

在通过channel.txSelect 方法开启事务之后,我们便可以发布消息给RabbitMQ了,如果事务提交成功,则消息一定到达了MQ,如果MQ异常崩溃或者其他原因出现异常,这个时候我们便可以将其捕获,进而通过执行channel.txRollback回滚事务。

在这里插入图片描述
AQMP协议流转过程
在这里插入图片描述
开启事务和不开启相比多了四个步骤:

  • 客户端发送tx.select,将信道置为事务模式。
  • Broker回复tx.select-ok,确认已将信道置为事务模式。
  • 在发送完消息之后,客户端发送Tx.commit提交事务。
  • Broker回复Tx.commit-ok,确认事务提交。

事务回滚样例
在这里插入图片描述AQMP协议流转过程
在这里插入图片描述

事务确实能够解决发送方和MQ之间消息确认的问题,只有消息成功被MQ接收,事务才能提交成功。但是,使用事务机制会吸干MQ性能

发送方确认机制

事务机制在一条消息发送出去之后会使发送端阻塞,以等待MQ的回应,之后才能发送下一条消息。相比之下,发送方确认机制的好处在于它是异步的 (一边发送,一边等待确认),一旦发布一条消息,生产者应用程序就可以在等信道返回确认的同时继续发送下一条消息,当消息最终得到确认之后,生产者应用程序便可以通过回调方法来处理该消息。如果MQ因为自身内部错误导致消息丢失,就会发送一条nack(Basic.Nack)命令。

生产者将信道设置成confirm模式,一旦信道进入confirm模式,所有在该信道上面发布的消息都会被指派一个唯一的ID(从1开始递增),一旦消息被投递到所有匹配的队列之后,MQ会发送一个确(Basic.ACK)给生产者(包含唯一的ID),如果消息和队列是持久化的,消息会在写入磁盘之后发出。MQ也可以设置channel.basicAck中的mutiple参数,表示到这个序号之前的所有消息都已经得到了处理

在这里插入图片描述
生产者confirm模式示例代码
在这里插入图片描述在这里插入图片描述
AQMP协议流转过程
在这里插入图片描述
事务机制和发送方确认机制QPS对比
在这里插入图片描述
QPS虽然有提升,但是完全没有达到预想的效果,关键在于:上述confirm模式每次发送一条消息之后就调用channel.waitForConfirms方法,等待服务端确认,此时就退化成了串行同步等待

而为什么又比事务机制快一点,核心在于:

confirm机制通信交互的命令是两条Basic.publish和Basic.Ack;

事务机制是3条:Basic.Publish、Tx.Commit、Tx.Commit-Ok,事务机制相比之下多了一个报文帧。

注意:事务机制和confirm机制确保的是消息能够被正确的发送至交换器,如果此交换器没有匹配的队列,那么消息也会丢失。所以在使用这两种机制的时候要确保所涉及的交换器能够有匹配的队列。更进一步的说,发送方要配合mandatory参数或者备份交换器使用来提高消息传输的可靠性

对于confirm模式的改进,有如下两种

  • 批量confirm方法:每次发送一批消息后,调用channel.waitForConfirms方法,等待服务器的确认返回。
  • 异步confirm方法:提供一个回调方法,服务端确认一条或者多条消息后客户端会回调这个方法进行处理。

1. 批量confirm

在批量confirm方法中,客户端定期或者定量调用channel.waitForConfirms等待MQ确认返回,批量极大提高了confirm的效率,但是 问题在于出现Basic.Nack或者超时情况时,客户端需要将这一批次的消息全部重发。会带来明显的重复消息数,如果消息经常丢失,批量confirm性能反而下降。

批量confirm示例
在这里插入图片描述

2. 异步confirm

异步Confirm在客户端channel接口中提供addConfirmListener方法,添加ConfirmListener这个回调接口,这个接口包含两个方法:handleAck和handleNack。分别用来处理Basic.Ack和Basic.Nack。我们需要为每一个信道维护一个“unconfirm”消息序号集合,每发送一条消息,集合元素加1.每当调用ConfirmListener中的handleAck方法时,匹配unconfirm集合中元素进行处理。集合优先采用SortedSet集合。

示例代码
在这里插入图片描述
QPS测试对比
在这里插入图片描述

消费者要点

消息分发

当RabbitMQ队列拥有多个消费者时,队列收到的消息将以轮询的分发方式发送给消费者。每条消息只会发送给订阅列表里的一个消费者。当消费者端负载加重时,只需要创建更多的消费者来消费处理消息即可。

很多时候轮询分分发机制也不是那么优雅,比如,某些消费者任务繁重,来不及消费那么多消息,而某些其他消费者由于机器性能卓越很快处理完所分配到的消息,进而空闲,这样就会造成整体应用的吞吐量下降。

在订阅消费队列之前,消费端程序调用channel.basicQos(5) ,允许信道上的消费者保持最大未确认的消息数为5,之后订阅某个队列进行消费。RabbitMQ会保存一个消费者列表,每发送一条消息都会为对应的消费者计数,如果该 消费者达到了设定的上限,MQ就不会向这个消费者在发送任何消息。直到消费者确认了某条消息。这种机制类似于TCP/IP中的滑动窗口。

消息传输保障

一般消息中间件的消息传输保障分为三个层级

  • At most once : 最多一次。消息可能会丢失,但绝不会重复传输。
  • At least once : 最少一次,消息绝不会丢失,但可能会重复。
  • Exactly once : 恰好一次,每条消息肯定会被传输一次且仅传输一次。

RabbitMQ支持“最多一次”和“最少一次”,其中最少一次投递实现需要考虑以下几方面

  • 消息生产者需要开启事务机制或者 confirm机制,以确保消息可以可靠传输到RabbitMQ中。
  • 消息生产者需要配合使用mandatory参数或者备份交换机来确保消息能够从交换器路由到队列中,进而能够保存下来而不会被丢弃。
  • 消息和队列都需要持久化处理,以确保RabbitMQ服务器在遇到异常的情况时不会造成丢失。
  • 消费者在消费消息的同时将autoAck设置为false,然后通过手动确认的方式去确认已经正确消费的消息,以避免在消费端引起不必要的消息丢失。

“最多一次”就无须考虑上述方面,生产者虽已发送,消费者随意消费,不过很难确保消息不会丢失。

“恰好一次”是RabbitMQ目前无法保证的。一般可以使用去重机制(例如借助Redis)加上“最少一次”进行处理

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

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

相关文章

树莓派Pico

树莓派Pico是树莓派基金会推出的一款基于RP2040微控制器的微型计算机板&#xff0c;它是专为需要高性能微控制器的应用场景设计的&#xff0c;特别适合于需要实时控制、低功耗和小型化解决方案的项目。以下是树莓派Pico的详细介绍&#xff1a; ### 核心特点&#xff1a; - **基…

NAND闪存原厂铠侠加速推上市,预计10月完成IPO

NAND闪存原厂铠侠Kioxia拟趁着半导体市场回暖及企业财务状况显著提升的契机&#xff0c;加速推进其上市进程。 据报道&#xff0c;公司计划最快于8月底提交IPO申请&#xff0c;目标是在2024年10月末于东京证券交易所完成首次公开募股。此番上市动作不仅反映出市场复苏迹象&…

使用el-amap-info-window遇到的问题

使用的这个库https://github.com/yangyanggu/vue-amap 想要滚动amapInfoWindow里的内容&#xff0c;但不触发地图缩放 默认滚动amapInfoWindow里的内容&#xff0c;会触发地图缩放。看了C站一个大佬的文章解决了。 amapInfoWindow会自动滚动到顶部 我的amapInfoWindow里面用了…

【python】一篇文零基础到入门:快来玩吧~

本笔记材料源于&#xff1a; PyCharm | 创建你的第一个项目_哔哩哔哩_bilibili Python 语法及入门 &#xff08;超全超详细&#xff09; 专为Python零基础 一篇博客让你完全掌握Python语法-CSDN博客 0为什么安装python和pycharm&#xff1f; 不同于c&#xff0c;c&#xff0…

Windows server 2016.2019 .NET Framework 3.5安装包、安装步骤

windows server2019 操作系统 安装 sqlserver2008时提示缺少 .NET Frameword 3.5&#xff0c; 在功能里选择 .NET Frameword 3.5安装报错&#xff0c; 下载安装包&#xff0c;下载地址 https://download.csdn.net/download/qq445829096/89450429这里指定备份源路径 安装包解…

【应用开发二】GPIO操控(输出、输入、中断)

1 操控GPIO方式 控制目录&#xff1a;/sys/class/gpio /sys/class/gpio目录下文件如下图所示&#xff1a; 1.1 gpiochipX目录 功能&#xff1a;当前SoC所包含的所有GPIO控制器 i.mx6ull一共包含5个GPIO控制器&#xff0c;分别为GPIO1~5分别对应gpiochip0、gpiochip32、gpi…

javaSE知识点整理总结(上)

目录 一、面向对象 1. 类、对象、方法 2.面向对象三大特征 &#xff08;1&#xff09;封装 &#xff08;2&#xff09;继承 &#xff08;3&#xff09;多态 二、常用类 1.Object类 2.Array类 3.基本数据类型包装类 4.String类 5.StringBuffer类 6.Math类 7.Random…

韩顺平0基础学java——第32天

p638-652 Properties类 list&#xff1a;这个设备可以是一个流对象。 修改&#xff1a;如果该文件里没有Key&#xff0c;那即是创建&#xff0c;如果是有那就是修改。 继续坦克大战 防止敌人坦克重叠 满脑子都是今汐&#xff0c;亚达哟&#x1f62d;&#x1f62d;&#x1f6…

关于Mac mini 10G网口的问题

问题: 购入一个10G网口的Mac mini M2&#xff0c;将其和自己的2.5G交换机连接&#xff0c;使用共享屏幕进行远程操作的过程中出现了频率极高的卡顿&#xff0c;几乎是几秒钟卡一下&#xff0c;使用ping进行测试发现卡的时候就ping不通了。测试使用Mac mini的无线网和雷电转2.5G…

PSA制氮装置在化工行业的应用解析

PSA制氮装置作为一种可靠的氮气制备技术&#xff0c;在化工行业中发挥着越来越重要的作用。本文将详细探讨PSA制氮装置在化工行业的应用。 一、PSA制氮装置的工作原理 PSA制氮装置通过吸附剂的吸附选择性&#xff0c;在高压下吸附原料气中的杂质成分&#xff0c;如氧气、水蒸气…

微服务部署上线过程总结

目录 一、找到适合自己的部署方式 二、开始部署&#xff0c;先安装需要的环境 2.1 梳理一下都需要安装什么软件 2.2 配置数据库环境 2.3 配置redis 2.4 配置nacos 2.5 配置rabbitmq 2.6 配置docker环境 三、环境配置好了&#xff0c;开始部署后端 3.1 梳理后端都…

佛山禅城电脑城维修1台联想3650M5服务器 黄灯故障

佛山禅城一同行客户通过CSDN找到我们&#xff0c;经过对接&#xff0c;确认好服务器型号&#xff0c;和服务器大致故障&#xff0c;跟客户仔细的分析了引起故障大致的原因和解决的方式方法后&#xff0c;经过商务沟通&#xff0c;该同行考虑由我们安排工程师带配件到佛山禅城电…

光伏设计:光伏项目开发中最关键的一环

随着全球对可再生能源的需求不断增长&#xff0c;光伏技术作为其中的佼佼者&#xff0c;已经成为许多国家实现能源转型和应对气候变化的重要手段。在光伏项目的开发过程中&#xff0c;光伏设计作为最关键的一环&#xff0c;其重要性不言而喻。本文将从光伏设计的角度&#xff0…

【自然语言处理系列】手动安装和测试Spacy中en_core_web_sm模型的详细教程

摘要&#xff1a;本教程旨在为自然语言处理&#xff08;NLP&#xff09;初学者提供一个详细的指南&#xff0c;用于手动安装流行的NLP库Spacy及其英语模型en_core_web_sm。文章将逐步指导您如何安装Spacy库、查看其版本&#xff0c;确定并下载适合的en_core_web_sm模型版本&…

深度之眼(二十七)——神经网络基础知识(二)

文章目录 一、反向传播1.1 梯度下降法1.2 学习率 二、损失函数2.1 两种常见的损失函数2.2 CE&#xff08;交叉熵&#xff09;2.3 其他的损失函数和网址 三、权值初始化3.1 自适应标准差&#xff1a;自适应方法随机分布中的标准差 四、正则化方法4.1 过拟合、方差、偏差、噪声4.…

Redis主从复制、哨兵以及Cluster集群

1.Redis高可用 在web服务器中&#xff0c;高可用是指服务器可以正常访问的时间&#xff0c;衡量的标准是在多长时间内可以提供正常服务&#xff08;99.9%、99.99%、99.999%等等&#xff09;。 但是在Redis语境中&#xff0c;高可用的含义似乎要宽泛一些&#xff0c;除了保证提供…

嵌入式Linux的浮点运算能力测试

嵌入式Linux的浮点运算能力测试 今天需要对一款ARM CPU的浮点数运算能力进行测试&#xff0c;采用了台式机上常用的SuperPI相同的原理&#xff1a;计算一定小数位数的圆周率来测试硬件的浮点数计算能力和稳定性。 首先下载计算软件的源代码&#xff0c;可以使用下面命令&#…

阿里云常用的操作

阿里云常见的产品和服务 容器服务 可以查看容器日志、监控容器cpu和内存&#xff0c; 日志服务 SLS 可以查看所有服务的日志&#xff0c; Web应用防火墙 WAF 可以查看 QPS. 阿里云查看集群&#xff1a; 点击 “产品和服务” 中的 容器服务&#xff0c;可以查看 集群列表&…

Labview_Occurrencel(事件发生)

PS&#xff1a;这里遇到 一个很Low的事情&#xff1a; 在停止第二个while循环的时候出现了停止不了的情况。因为等待事件发生设置的超时时间为:-1。所以等事件发生后出现了条件接线端已经执行的情况&#xff0c;所以当下次事件发生时未能及时停止。初版的停止设置如下图&#x…

Raylib学习-鼠标检测与GPU缓冲区使用

鼠标左键点击运行绘制 #include <raylib.h>int main() {const int screenWidth 800;const int screenHeight 450;InitWindow(screenWidth, screenHeight, "test"); // 设置帧率SetTargetFPS(150); // 设置一个画布&#xff0c;可以使用GPU进行绘制RenderText…