RocketMQ学习笔记(持续更新中......)

news2025/1/3 20:27:30

目录

1. 单机搭建

2. 测试RocketMQ

3. 集群搭建

4. 集群启动 

5. RocketMQ-DashBoard搭建

6. 不同类型消息发送

1.同步消息

2. 异步消息发送

3. 单向发送消息

7. 消费消息


1. 单机搭建

1. 先从rocketmq官网下载二进制包,ftp上传至linux服务器,unzip命令解压。

2. 启动NameServer

# 1.启动NameServer
nohup sh bin/mqnamesrv &
# 2.查看启动日志
tail -f ~/logs/rocketmqlogs/namesrv.log

3. 启动Broker

RocketMQ默认的虚拟机内存较大,启动Broker如果因为内存不足失败,需要编辑如下两个配置文件,修改JVM内存大小。

# 编辑runbroker.sh和runserver.sh修改默认JVM大小
vi runbroker.sh
vi runserver.sh
  • 参考设置:

JAVA_OPT="${JAVA_OPT} -server -Xms256m -Xmx256m -Xmn128m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"

# 1.启动Broker
nohup sh bin/mqbroker -n localhost:9876 &
# 2.查看启动日志
tail -f ~/logs/rocketmqlogs/broker.log 

2. 测试RocketMQ

1. 发送消息

# 1.设置环境变量
export NAMESRV_ADDR=localhost:9876
# 2.使用安装包的Demo发送消息
sh bin/tools.sh org.apache.rocketmq.example.quickstart.Producer

2. 接收消息

# 1.设置环境变量
export NAMESRV_ADDR=localhost:9876
# 2.接收消息
sh bin/tools.sh org.apache.rocketmq.example.quickstart.Consumer

3. 关闭RocketMQ

# 1.关闭NameServer
sh mqshutdown namesrv
# 2.关闭Broker
sh mqshutdown broker

3. 集群搭建

这里采用broker双主双从(同步模式),NameServer、Producer、Producer集群由于无状态性,搭建简单。(Master和Slave的brokerName相同,brokerId不同)

1. 服务器环境

序号IP角色架构模式
1192.168.183.132nameserver、brokerserverMaster1、Slave2
2192.168.183.128nameserver、brokerserverMaster2、Slave1

2. hosts配置(两台一样配置)

vi /etc/hosts

# 重启网卡
systemctl restart network

3. 防火墙关闭

# 关闭防火墙
systemctl stop firewalld.service 
# 查看防火墙的状态
firewall-cmd --state 
# 禁止firewall开机启动
systemctl disable firewalld.service

4. 创建消息存储路径

mkdir -p /root/store/master1
mkdir -p /root/store/master1/commitlog
mkdir -p /root/store/master1/consumequeue
mkdir -p /root/store/master1/index


mkdir -p /root/store/slave2
mkdir -p /root/store/slave2/commitlog
mkdir -p /root/store/slave2/consumequeue
mkdir -p /root/store/slave2/index


mkdir -p /root/store/master2
mkdir -p /root/store/master2/commitlog
mkdir -p /root/store/master2/consumequeue
mkdir -p /root/store/master2/index


mkdir -p /root/store/slave1
mkdir -p /root/store/slave1/commitlog
mkdir -p /root/store/slave1/consumequeue
mkdir -p /root/store/slave1/index

5. broker配置文件

1)master1

服务器:192.168.183.132

vi /root/rocketmq4.4/conf/2m-2s-sync/broker-a.properties
# 所属集群名称
brokerClusterName=rocketmq-cluster
# broker名字,注意:不同的broker名字必须不同
brokerName=broker-a
# brokerId, brokerId=0表示Master,大于0表示Slave
brokerId=0
brokerIP1=rocketmq-master1
# nameserver地址,分号分隔
namesrvAddr=rocketmq-nameserver1:9876;rocketmq-nameserver2:9876
# 在发送消息时,自动创建服务器不存在的topic,默认创建的队列数
defalutTopicQueueNums=4
# 是否允许自动创建Topic,建议线下环境开启,线上环境关闭
autoCreateTopicEnable=true
# 是否允许自动创建订阅组,建议线下环境开启,线上环境关闭
autoCreateSubscriptionGroup=true
# Broker 对外暴露端口
listenPort=10911
# 删除文件时间点,默认凌晨4点
deleteWhen=04
# 文件保留时间,默认48小时(测试环境建议设置120分钟)
fileReservedTime=120
# commitlog文件大小,默认1G
mapedFileSizeCommitLog=1073741824
# ConsumeQueue每个文件默认存30w条,根据业务情况调整
mapedFileSizeConsumeQueue=300000
# 检测物理文件磁盘空间
disMaxUsedSpaceRatio=88

#存储路径
storePathRootDir=/root/store/master1
#commitLog 存储路径
storePathCommitLog=/root/store/master1/commitlog
#消费队列存储路径存储路径
storePathConsumeQueue=/root/store/master1/consumequeue
#消息索引存储路径
storePathIndex=/root/store/master1/index
#checkpoint 文件存储路径
storeCheckpoint=/root/store/master1/checkpoint
#abort 文件存储路径
abortFile=/root/store/master1/abort

# 限制消息的大小
maxMessageSize=65536

# Broker角色
brokerRole=SYNC_MASTER
# 刷盘方式
flushDiskType=SYNC_FLUSH

2)slave2

服务器:192.168.183.132

vi /root/rocketmq4.4/conf/2m-2s-sync/broker-b-s.properties
# 所属集群名称
brokerClusterName=rocketmq-cluster
# broker名字,注意:不同的broker名字必须不同
brokerName=broker-b
# brokerId, brokerId=0表示Master,大于0表示Slave
brokerId=1
brokerIP1=rocketmq-slave2
# nameserver地址,分号分隔
namesrvAddr=rocketmq-nameserver1:9876;rocketmq-nameserver2:9876
# 在发送消息时,自动创建服务器不存在的topic,默认创建的队列数
defalutTopicQueueNums=4
# 是否允许自动创建Topic,建议线下环境开启,线上环境关闭
autoCreateTopicEnable=true
# 是否允许自动创建订阅组,建议线下环境开启,线上环境关闭
autoCreateSubscriptionGroup=true
# Broker 对外暴露端口
listenPort=11011
# 删除文件时间点,默认凌晨4点
deleteWhen=04
# 文件保留时间,默认48小时(测试环境建议设置120分钟)
fileReservedTime=120
# commitlog文件大小,默认1G
mapedFileSizeCommitLog=1073741824
# ConsumeQueue每个文件默认存30w条,根据业务情况调整
mapedFileSizeConsumeQueue=300000
# 检测物理文件磁盘空间
disMaxUsedSpaceRatio=88

#存储路径
storePathRootDir=/root/store/slave2
#commitLog 存储路径
storePathCommitLog=/root/store/slave2/commitlog
#消费队列存储路径存储路径
storePathConsumeQueue=/root/store/slave2/consumequeue
#消息索引存储路径
storePathIndex=/root/store/slave2/index
#checkpoint 文件存储路径
storeCheckpoint=/root/store/slave2/checkpoint
#abort 文件存储路径
abortFile=/root/store/slave2/abort

# 限制消息的大小
maxMessageSize=65536

# Broker角色
brokerRole=SLAVE
# 刷盘方式
flushDiskType=ASYNC_FLUSH

3)master2

服务器:192.168.183.128

vi /root/rocketmq4.4/conf/2m-2s-sync/broker-b.properties
# 所属集群名称
brokerClusterName=rocketmq-cluster
# broker名字,注意:不同的broker名字必须不同
brokerName=broker-b
# brokerId, brokerId=0表示Master,大于0表示Slave
brokerId=0
brokerIP1=rocketmq-master2
# nameserver地址,分号分隔
namesrvAddr=rocketmq-nameserver1:9876;rocketmq-nameserver2:9876
# 在发送消息时,自动创建服务器不存在的topic,默认创建的队列数
defalutTopicQueueNums=4
# 是否允许自动创建Topic,建议线下环境开启,线上环境关闭
autoCreateTopicEnable=true
# 是否允许自动创建订阅组,建议线下环境开启,线上环境关闭
autoCreateSubscriptionGroup=true
# Broker 对外暴露端口
listenPort=10911
# 删除文件时间点,默认凌晨4点
deleteWhen=04
# 文件保留时间,默认48小时(测试环境建议设置120分钟)
fileReservedTime=120
# commitlog文件大小,默认1G
mapedFileSizeCommitLog=1073741824
# ConsumeQueue每个文件默认存30w条,根据业务情况调整
mapedFileSizeConsumeQueue=300000
# 检测物理文件磁盘空间
disMaxUsedSpaceRatio=88

#存储路径
storePathRootDir=/root/store/master2
#commitLog 存储路径
storePathCommitLog=/root/store/master2/commitlog
#消费队列存储路径存储路径
storePathConsumeQueue=/root/store/master2/consumequeue
#消息索引存储路径
storePathIndex=/root/store/master2/index
#checkpoint 文件存储路径
storeCheckpoint=/root/store/master2/checkpoint
#abort 文件存储路径
abortFile=/root/store/master2/abort

# 限制消息的大小
maxMessageSize=65536

# Broker角色
brokerRole=SYNC_MASTER
# 刷盘方式
flushDiskType=SYNC_FLUSH

4)slave1

服务器:192.168.183.128

vi /root/rocketmq4.4/conf/2m-2s-sync/broker-a-s.properties
# 所属集群名称
brokerClusterName=rocketmq-cluster
# broker名字,注意:不同的broker名字必须不同
brokerName=broker-a
# brokerId, brokerId=0表示Master,大于0表示Slave
brokerId=1
brokerIP1=rocketmq-slave1
# nameserver地址,分号分隔
namesrvAddr=rocketmq-nameserver1:9876;rocketmq-nameserver2:9876
# 在发送消息时,自动创建服务器不存在的topic,默认创建的队列数
defalutTopicQueueNums=4
# 是否允许自动创建Topic,建议线下环境开启,线上环境关闭
autoCreateTopicEnable=true
# 是否允许自动创建订阅组,建议线下环境开启,线上环境关闭
autoCreateSubscriptionGroup=true
# Broker 对外暴露端口
listenPort=11011
# 删除文件时间点,默认凌晨4点
deleteWhen=04
# 文件保留时间,默认48小时(测试环境建议设置120分钟)
fileReservedTime=120
# commitlog文件大小,默认1G
mapedFileSizeCommitLog=1073741824
# ConsumeQueue每个文件默认存30w条,根据业务情况调整
mapedFileSizeConsumeQueue=300000
# 检测物理文件磁盘空间
disMaxUsedSpaceRatio=88

#存储路径
storePathRootDir=/root/store/slave1
#commitLog 存储路径
storePathCommitLog=/root/store/slave1/commitlog
#消费队列存储路径存储路径
storePathConsumeQueue=/root/store/slave1/consumequeue
#消息索引存储路径
storePathIndex=/root/store/slave1/index
#checkpoint 文件存储路径
storeCheckpoint=/root/store/slave1/checkpoint
#abort 文件存储路径
abortFile=/root/store/slave1/abort

# 限制消息的大小
maxMessageSize=65536

# Broker角色
brokerRole=SLAVE
# 刷盘方式
flushDiskType=ASYNC_FLUSH

4. 集群启动 

1)启动NameServe集群

分别在192.168.183.132和192.168.183.128启动NameServer

nohup sh mqnamesrv &

启动成功。

2)启动broker集群

  • 在192.168.183.132上启动master1和slave2
# master1
nohup sh mqbroker -c /root/rocketmq4.4/conf/2m-2s-sync/broker-a.properties &
# slave2
nohup sh mqbroker -c /root/rocketmq4.4/conf/2m-2s-sync/broker-b-s.properties &

启动成功。

  • 在192.168.183.128上启动master2和slave1
# slave1
nohup sh mqbroker -c /root/rocketmq4.4/conf/2m-2s-sync/broker-a-s.properties &
# master2
nohup sh mqbroker -c /root/rocketmq4.4/conf/2m-2s-sync/broker-b.properties &

3)日志查看

# 查看nameServer日志
tail -500f ~/logs/rocketmqlogs/namesrv.log
# 查看broker日志
tail -500f ~/logs/rocketmqlogs/broker.log

5. RocketMQ-DashBoard搭建

github上拉取项目后,修改yml的namesrvAddrs即可。

6. 不同类型消息发送

pom.xml

        <dependency>
            <groupId>org.apache.rocketmq</groupId>
            <artifactId>rocketmq-client</artifactId>
            <version>4.4.0</version>
        </dependency>

1.同步消息

SyncProducer.java 

/**
 * 发送同步消息
 */
public class SyncProducer {
    public static void main(String[] args) throws MQClientException, UnsupportedEncodingException, MQBrokerException, RemotingException, InterruptedException {
        // 实例化消息生产者Producer
        DefaultMQProducer producer = new DefaultMQProducer("group1");
        // 设置NameServer地址
        producer.setNamesrvAddr("192.168.183.132:9876;192.168.183.128:9876");
        // 启动Producer实例
        producer.start();
        for (int i = 0; i < 10; i++) {
            // 创建消息,并指定Topic,Tag,消息体
            Message msg = new Message("TopicTest",
                    "TagA",
                    ("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET)
                    );
            // 发送消息到broker
            SendResult sendResult = producer.send(msg);
            // 发送状态
            SendStatus status = sendResult.getSendStatus();
            // 消息ID
            String msgId = sendResult.getMsgId();
            // 消息接收队列ID
            int queueId = sendResult.getMessageQueue().getQueueId();
            System.out.println("发送状态: " + status + " 消息ID: " + msgId + " 消息接收队列ID: " + queueId);
            TimeUnit.SECONDS.sleep(1);
        }
        // 如果不再发送消息,关闭Producer实例
        producer.shutdown();
    }
}

2. 异步消息发送

 AsyncProducer1.java


public class AsyncProducer1 {
    public static void main(String[] args) throws MQClientException, UnsupportedEncodingException, RemotingException, InterruptedException {
        // 实例化消息生产者Producer
        DefaultMQProducer producer = new DefaultMQProducer("group1");
        // 设置NameServer地址
        producer.setNamesrvAddr("192.168.183.132:9876;192.168.183.128:9876");
        // 启动Producer实例
        producer.start();
        // 设置重试次数
        producer.setRetryTimesWhenSendAsyncFailed(0);
        for (int i = 0; i < 10; i++) {
            // 创建消息,并指定Topic,Tag,消息体
            Message msg = new Message("TopicTest",
                    "TagB",
                    ("Hello World " + i).getBytes(RemotingHelper.DEFAULT_CHARSET)
            );
            // SendCallback 接收异步返回结果的回调
            int finalI = i;
            producer.send(msg, new SendCallback() {
                @Override
                public void onSuccess(SendResult sendResult) {
                    System.out.println("发送结果:" + sendResult);
                }

                @Override
                public void onException(Throwable throwable) {
                    System.out.println("发送异常:" + throwable);
                }
            });
            TimeUnit.SECONDS.sleep(1);
        }
        producer.shutdown();
    }
}

3. 单向发送消息

不关心结果,比如日志发送

public class OnewayProducer {
	public static void main(String[] args) throws Exception{
    	// 实例化消息生产者Producer
        DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name");
    	// 设置NameServer的地址
        producer.setNamesrvAddr("192.168.183.132:9876;192.168.183.128:9876");
    	// 启动Producer实例
        producer.start();
    	for (int i = 0; i < 100; i++) {
        	// 创建消息,并指定Topic,Tag和消息体
        	Message msg = new Message("TopicTest" /* Topic */,
                "TagA" /* Tag */,
                ("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET) /* Message body */
        	);
        	// 发送单向消息,没有任何返回结果
        	producer.sendOneway(msg);

    	}
    	// 如果不再发送消息,关闭Producer实例。
    	producer.shutdown();
    }
}

7. 消费消息


public class Consumer1 {
    public static void main(String[] args) throws MQClientException {
        // 实例化消费者,指定组名
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("group1");
        // 指定NameServer地址信息
        consumer.setNamesrvAddr("192.168.183.132:9876;192.168.183.128:9876");
        // 订阅Topic
        consumer.subscribe("TopicTest", "*");
        // 负载均衡模式消费
        consumer.setMessageModel(MessageModel.CLUSTERING);   // 广播模式 MessageModel.BROADCASTING
        // 注册回调函数,处理消息
        consumer.registerMessageListener(new MessageListenerConcurrently() {
            @Override
            public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
                System.out.println(Thread.currentThread().getName() + " " + msgs);
                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            }
        });
        // 启动消费者
        consumer.start();
        System.out.println("Consumer Started.");
    }
}

负载均衡模式消费:多个消费者共同处理broker消息队列的消息。

广播模式消费:每个消费者都会收到订阅的Topic的消息。

持续更新中......

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

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

相关文章

【二】arcgis JavaScript api 实现加载不同坐标系的底图和三维服务

提示&#xff1a;如果是天地图底图参考这篇文章 【一】arcgis JavaScript api 实现加载不同坐标系的底图和三维服务_arcgis js api 调用三维地图服务-CSDN博客 需求&#xff1a; 前端开发实现底图&#xff08;wkid&#xff1a;3857&#xff0c;web墨卡托&#xff09;&#x…

PDF怎么压缩得又小又清晰?5种PDF压缩方法

PDF 文件在日常办公与学习中使用极为频繁&#xff0c;可想要把它压缩得又小又清晰却困难重重。一方面&#xff0c;PDF 格式本身具有高度兼容性&#xff0c;集成了文字、图像、矢量图等多样元素&#xff0c;压缩时难以兼顾不同元素特性&#xff0c;稍不注意&#xff0c;文字就会…

数据结构与算法之动态规划: LeetCode 62. 不同路径 (Ts版)

不同路径 https://leetcode.cn/problems/unique-paths/description/ 描述 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “…

Edge如何获得纯净的启动界面

启动Edge会出现快速链接&#xff0c;推广链接&#xff0c;网站导航&#xff0c;显示小组件&#xff0c;显示信息提要&#xff0c;背景 ●复杂页面 ●精简页面 点击页面设置按钮 关闭快速链接 关闭网站导航 关闭小组件 关闭信息提要 关闭背景 关闭天气提示 精简页面看起来十分舒…

如何利用java爬虫获得AMAZON商品详情

在数字化时代&#xff0c;数据的价值不言而喻&#xff0c;尤其是对于电商平台而言&#xff0c;获取商品的详细信息对于优化用户体验、制定营销策略至关重要。亚马逊作为全球最大的电商平台之一&#xff0c;拥有海量的商品信息。本文将介绍如何使用Java编写爬虫程序&#xff0c;…

人工智能基础软件-Jupyter Notebook

简介&#xff1a; Jupyter Notebook是基于网页的用于交互计算的应用程序。其可被应用于全过程计算&#xff1a;开发、文档编写、运行代码和展示结果。 Jupyter Notebook是以网页的形式打开&#xff0c;可以在网页页面中直接编写代码和运行代码&#xff0c;代码的运行结果也会直…

数据库系列之分布式数据库下误删表怎么恢复?

数据的完整性是数据库可用性的基本功能&#xff0c;在实际应用数据库变更操作过程中可能因为误操作导致误删表或者truncate操作影响业务的正常访问。本文介绍了分布式数据库中在误删表场景下的数据恢复方案&#xff0c;并进行了对比。 1、数据库误删表恢复方案 应用数据的完整…

【分布式缓存中间件Memcached原理与应用】

分布式缓存中间件&#xff08;以 Memcached 为例&#xff09; 一、分布式缓存中间件概述 &#xff08;一&#xff09;概念 分布式缓存中间件是一种用于存储频繁访问的数据副本的软件系统&#xff0c;它位于应用程序和数据源&#xff08;通常是数据库&#xff09;之间。通过在…

No.2十六届蓝桥杯备战|练习题4道|数据类型|字符型|整型|浮点型|布尔型|signed|unsigned(C++)

B2002 Hello,World! - 洛谷 #include <iostream> using namespace std; int main() { cout << "Hello,World!" << endl; return 0; }打印飞机 #include <iostream> using namespace std;int main() {cout << " …

mysql系列7—Innodb的redolog

背景 本文涉及的内容较为底层&#xff0c;做了解即可&#xff0c;是以前学习《高性能Mysql》和《mysql是怎样运行的》的笔记整理所得。 redolog(后续使用redo日志表示)的核心作用是保证数据库的持久性。 在mysql系列5—Innodb的缓存中介绍过&#xff1a;数据和索引保存在磁盘上…

小程序租赁系统开发的优势与应用探索

内容概要 在如今这个数码科技飞速发展的时代&#xff0c;小程序租赁系统开发仿佛是一张神奇的魔法卡&#xff0c;能让租赁体验变得顺畅如丝。想象一下&#xff0c;无论你需要租用什么&#xff0c;从单车到房屋&#xff0c;甚至是派对用品&#xff0c;只需动动手指&#xff0c;…

太速科技-135-4路250Msps 16bit AD采集PCIe卡

4路250Msps 16bit AD采集PCIe卡 一、板卡概述 板卡为四路250M频率采集卡&#xff0c;可以实现四路高速的模拟数据转换到PCI-E总线上。板载两颗250M采样频率的高性能AD芯片&#xff08;ADS42LB69&#xff09;&#xff0c;数据输出模式为LVDS&#xff08;DDR&#xff09…

如何恢复永久删除的PPT文件?查看数据恢复教程!

可以恢复永久删除的PPT文件吗&#xff1f; Microsoft PowerPoint应用程序是一种应用广泛的演示程序&#xff0c;在人们的日常生活中经常使用。商人、官员、学生等在学习和工作中会使用PowerPoint做报告和演示。PowerPoint在人们的学习和工作生活中占主导地位&#xff0c;每天都…

Windows电脑带有日历的桌面备忘记事工具

工作计划、备忘清单、会议文件等怎么能化繁琐为简约&#xff0c;统统存储在一个记事工具中呢&#xff1f;Windows电脑上的备忘记事工具哪一款好用呢&#xff1f;推荐大家可关注敬业签&#xff0c;敬业签是一款集备忘、提醒和日历等功能于一体的桌面记事工具&#xff0c;可悬挂桌…

SSA-Transformer拿捏!麻雀搜索算法优化-Transformer多特征分类预测/故障诊断

SSA-Transformer拿捏&#xff01;麻雀搜索算法优化-Transformer多特征分类预测/故障诊断 目录 SSA-Transformer拿捏&#xff01;麻雀搜索算法优化-Transformer多特征分类预测/故障诊断效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现SSA-Transformer麻雀搜索…

STM32G070CB的USART1_RX引脚

简介 在使用STM32G070CBT6 的 USART1时&#xff0c;发现把 PA10作为 USART1_RX引脚时&#xff0c;接收不到数据。 问题排查 更换pin脚 使用PB6/PB7作为USART1_TX/RX&#xff0c; USART1 工作正常。 使用PA9/PB7作为USART1_TX/RX&#xff0c; USART1 同样工作正常。 示波器…

鸿蒙工程签名编译和上架

作为一个开发者&#xff0c;当你把自己的应用开发完了&#xff0c;准备上架到应用市场的时候&#xff0c;就需要用签名文件进行编译和应用上架了&#xff0c;本文介绍如何把一个鸿蒙工程进行签名编译和上架。 在平时开发中&#xff0c;我们可能关注签名不多&#xff0c;大家一般…

S7-1200 SCL PEEK 和 POKE 指令使用

使用S7-1200 SCL 编程语言的 PEEK 和 POKE 指令&#xff0c;可以实现对 I/O、M 存储器和数据块的读取或写入。 而通过 POKE_BLK 指令&#xff0c;还可以实现数据区域的复制或移动。 指令适用条件&#xff1a; 只用于 SCL 编程语言&#xff1b;软件从STEP7 Basic/Pro V11 SP2起…

绘制三元图、颜色空间图:R语言代码

本文介绍基于R语言中的Ternary包&#xff0c;绘制三元图&#xff08;Ternary Plot&#xff09;的详细方法&#xff1b;其中&#xff0c;我们就以RGB三色分布图为例来具体介绍。 三元图可以从三个不同的角度反映数据的特征&#xff0c;因此在很多领域都得以广泛应用&#xff1b;…

【2025 Rust学习 --- 09 特型和泛型】

特型和泛型 Rust 通过两个相关联的特性来支持多态&#xff1a;特型和泛型。许多 程序员熟悉这些概念&#xff0c;但 Rust 受到 Haskell 类型类&#xff08;typeclass&#xff09;的启发&#xff0c;采用 了一种全新的方式。 1、特型是 Rust 体系中的接口或抽象基类。乍一看&a…