news 2026/3/10 5:45:23

【消息队列项目】客户端搭建与测试

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【消息队列项目】客户端搭建与测试

目录

一.广播交换模式下的测试

1.1.生产者消费者代码编写

1.2.测试

二.直接交换模式下的测试

2.1.生产者消费者代码编写

2.2.测试

三.主题交换模式下的测试

3.1.生产者消费者代码编写

3.2.测试


搭建客户端

  • 发布消息的生产者客户端
  • 订阅消息的消费者客户端

思想

  • 必须要有一个生产者客户端
  • 声明一个交换机
  • 声明一个队列1,binding_key=queue1
  • 声明一个队列2,binding_key=news.music.#
  • 将两个队列和交换机绑定起来
  • 搭建两个消费者客户端,分别订阅一个队列的消息

测试

  • 第一次,将交换机类型设置为广播模式,理论结果两个消费者客户端都能拿到消息
  • 第二次,将交换机类型设置为直接交换模式,routing_key=queue1 ,理论结果,只有订阅了队列1消息的客户端能拿到消息
  • 第三次,将交换机类型设置为主题交换,routing_key=news.music.pop,理论结果只有订阅了队列2消息的客户端能拿到消息

一.广播交换模式下的测试

1.1.生产者消费者代码编写

生产者客户端实现

#include "connection.hpp" int main() { // 1. 创建异步工作线程对象,用于处理网络IO mymq::AsyncWorker::ptr awp = std::make_shared<mymq::AsyncWorker>(); // 2. 建立与RabbitMQ服务器的连接 mymq::Connection::ptr conn = std::make_shared<mymq::Connection>("127.0.0.1", 8085, awp); // 3. 通过连接创建信道 mymq::Channel::ptr channel = conn->openChannel(); // 4. 声明交换机和队列,并建立绑定关系 // 使用空的属性映射(不设置额外参数) google::protobuf::Map<std::string, std::string> tmp_map; // 4.1 声明一个名为"exchange1"的广播交换机(ExchangeType::FANOUT) // 参数:交换机名称、类型、是否持久化、是否自动删除、额外属性 channel->declareExchange("exchange1", mymq::ExchangeType::FANOUT, true, false, tmp_map); // 4.2 声明一个持久化队列"queue1" // 参数:队列名称、是否持久化、是否排他、是否自动删除、额外属性 channel->declareQueue("queue1", true, false, false, tmp_map); // 4.3 声明一个持久化队列"queue2" channel->declareQueue("queue2", true, false, false, tmp_map); // 4.4 将队列"queue1"绑定到交换机"exchange1" channel->queueBind("exchange1", "queue1", "queue1"); // 4.5 将队列"queue2"绑定到交换机"exchange1" channel->queueBind("exchange1", "queue2", "news.music.#"); // 5. 发布消息到交换机 // 发送10条消息,所有绑定队列都会收到 for (int i = 0; i < 10; i++) { // 发布消息:交换机名称、消息属性、消息内容 channel->basicPublish("exchange1", nullptr, "Hello World-" + std::to_string(i)); } // 6. 关闭信道 conn->closeChannel(channel); return 0; }

消费者

#include "connection.hpp" #include <iostream> #include <thread> #include <chrono> #include <functional> // 消息消费回调函数 // 参数: // channel: 消息通道指针,用于发送确认消息等操作 // consumer_tag: 消费者标签,标识不同的消费者 // bp: 消息基本属性,包含消息ID、路由键等信息 // body: 消息体内容 void cb(mymq::Channel::ptr &channel, const std::string consumer_tag, const mymq::BasicProperties *bp, const std::string &body) { // 打印消费者信息和接收到的消息内容 std::cout << consumer_tag << "消费了消息:" << body << std::endl; // 发送消息确认,告诉RabbitMQ消息已被成功处理 // 参数:消息唯一ID channel->basicAck(bp->id()); } int main(int argc, char *argv[]) { // 检查命令行参数:需要指定要消费的队列名称 if (argc != 2) { std::cout << "使用方法: ./consume_client <队列名称>\n"; std::cout << "示例: ./consume_client queue1\n"; return -1; } // 1. 创建异步工作线程对象,用于处理网络IO和消息回调 mymq::AsyncWorker::ptr awp = std::make_shared<mymq::AsyncWorker>(); // 2. 建立与RabbitMQ服务器的连接 // 参数:服务器地址、端口号、异步工作线程 mymq::Connection::ptr conn = std::make_shared<mymq::Connection>("127.0.0.1", 8085, awp); // 3. 通过连接创建信道,信道是执行AMQP操作的通道 mymq::Channel::ptr channel = conn->openChannel(); // 4. 声明交换机和队列,并建立绑定关系 // 使用空的属性映射(不设置额外参数) google::protobuf::Map<std::string, std::string> tmp_map; // 4.1 声明一个名为"exchange1"的直接交换机(ExchangeType::FANOUT) // 参数:交换机名称、类型、是否持久化、是否自动删除、额外属性 channel->declareExchange("exchange1", mymq::ExchangeType::FANOUT, true, false, tmp_map); // 4.2 声明一个持久化队列"queue1" // 参数:队列名称、是否持久化、是否排他、是否自动删除、额外属性 channel->declareQueue("queue1", true, false, false, tmp_map); // 4.3 声明一个持久化队列"queue2" channel->declareQueue("queue2", true, false, false, tmp_map); // 4.4 将队列"queue1"绑定到交换机"exchange1",绑定键为"queue1" // 参数:交换机名称、队列名称、绑定键 channel->queueBind("exchange1", "queue1", "queue1"); // 4.5 将队列"queue2"绑定到交换机"exchange1",绑定键为"news.music.#" // "#"是通配符,表示匹配多个单词 channel->queueBind("exchange1", "queue2", "news.music.#"); // 5. 使用std::bind创建回调函数适配器 // std::bind将回调函数cb与参数绑定,其中channel作为第一个参数固定传入 // std::placeholders::_1、_2、_3代表回调函数cb的consumer_tag、bp、body参数 auto functor = std::bind(cb, channel, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); // 6. 开始消费指定队列的消息 // 参数: // consumer1: 消费者标签,用于标识此消费者 // argv[1]: 队列名称,从命令行参数获取 // false: 是否自动确认消息,false表示需要手动确认(basicAck) // functor: 消息到达时的回调函数 channel->basicConsume("consumer1", argv[1], false, functor); // 7. 保持程序运行,等待消息 // 使用无限循环,每3秒休眠一次,避免CPU占用过高 while(1) { std::this_thread::sleep_for(std::chrono::seconds(3)); } // 8. 关闭信道(这里不会被执行,因为程序一直循环等待消息) conn->closeChannel(channel); return 0; }

makefile

all: publish_client consume_client publish_client: publish_client.cc ../third/include/muduo/protobuf/codec.cc ../mqcommon/msg.pb.cc ../mqcommon/proto.pb.cc g++ $^ -o $@ -I ../third/include -L ../third/lib -lmuduo_net -lmuduo_base -lpthread -lprotobuf -lz -lsqlite3 consume_client: consume_client.cc ../third/include/muduo/protobuf/codec.cc ../mqcommon/msg.pb.cc ../mqcommon/proto.pb.cc g++ $^ -o $@ -I ../third/include -L ../third/lib -lmuduo_net -lmuduo_base -lpthread -lprotobuf -lz -lsqlite3 .PHONY: clean clean: rm -rf publish_client consume_client

1.2.测试

没有问题,接下来我们就进入我们的测试环节

首先我们先启动服务器

服务器已经运行起来了

我们先运行消费者客户端

./consume_client queue1

换一个终端

./consume_client queue2

换一个终端

./publish_client

运行之后,我们发现绑定了queue1或者queue2的都收到了消息

二.直接交换模式下的测试

2.1.生产者消费者代码编写

生产者

#include "connection.hpp" int main() { // 1. 创建异步工作线程对象,用于处理网络IO mymq::AsyncWorker::ptr awp = std::make_shared<mymq::AsyncWorker>(); // 2. 建立与RabbitMQ服务器的连接 mymq::Connection::ptr conn = std::make_shared<mymq::Connection>("127.0.0.1", 8085, awp); // 3. 通过连接创建信道 mymq::Channel::ptr channel = conn->openChannel(); // 4. 声明交换机和队列,并建立绑定关系 // 使用空的属性映射(不设置额外参数) google::protobuf::Map<std::string, std::string> tmp_map; // 4.1 声明一个名为"exchange1"的直接交换机 // 参数:交换机名称、类型、是否持久化、是否自动删除、额外属性 channel->declareExchange("exchange1", mymq::ExchangeType::DIRECT, true, false, tmp_map); // 4.2 声明一个持久化队列"queue1" // 参数:队列名称、是否持久化、是否排他、是否自动删除、额外属性 channel->declareQueue("queue1", true, false, false, tmp_map); // 4.3 声明一个持久化队列"queue2" channel->declareQueue("queue2", true, false, false, tmp_map); // 4.4 将队列"queue1"绑定到交换机"exchange1" channel->queueBind("exchange1", "queue1", "queue1"); // 4.5 将队列"queue2"绑定到交换机"exchange1" channel->queueBind("exchange1", "queue2", "news.music.#"); // 5. 发布消息到交换机 // 发送4条消息,只有queue1能收到 for (int i = 0; i < 4; i++) { mymq::BasicProperties bp; bp.set_id(mymq::UUIDHelper::uuid()); // 设置消息唯一ID bp.set_delivery_mode(mymq::DeliveryMode::DURABLE); // 设置消息持久化 bp.set_routing_key("queue1"); // 设置路由键 // 发布消息:交换机名称、消息属性、消息内容 channel->basicPublish("exchange1", &bp, "Hello World-" + std::to_string(i)); } // 6. 关闭信道 conn->closeChannel(channel); return 0; }

消费者

#include "connection.hpp" #include <iostream> #include <thread> #include <chrono> #include <functional> // 消息消费回调函数 // 参数: // channel: 消息通道指针,用于发送确认消息等操作 // consumer_tag: 消费者标签,标识不同的消费者 // bp: 消息基本属性,包含消息ID、路由键等信息 // body: 消息体内容 void cb(mymq::Channel::ptr &channel, const std::string consumer_tag, const mymq::BasicProperties *bp, const std::string &body) { // 打印消费者信息和接收到的消息内容 std::cout << consumer_tag << "消费了消息:" << body << std::endl; // 发送消息确认,告诉RabbitMQ消息已被成功处理 // 参数:消息唯一ID channel->basicAck(bp->id()); } int main(int argc, char *argv[]) { // 检查命令行参数:需要指定要消费的队列名称 if (argc != 2) { std::cout << "使用方法: ./consume_client <队列名称>\n"; std::cout << "示例: ./consume_client queue1\n"; return -1; } // 1. 创建异步工作线程对象,用于处理网络IO和消息回调 mymq::AsyncWorker::ptr awp = std::make_shared<mymq::AsyncWorker>(); // 2. 建立与RabbitMQ服务器的连接 // 参数:服务器地址、端口号、异步工作线程 mymq::Connection::ptr conn = std::make_shared<mymq::Connection>("127.0.0.1", 8085, awp); // 3. 通过连接创建信道,信道是执行AMQP操作的通道 mymq::Channel::ptr channel = conn->openChannel(); // 4. 声明交换机和队列,并建立绑定关系 // 使用空的属性映射(不设置额外参数) google::protobuf::Map<std::string, std::string> tmp_map; // 4.1 声明一个名为"exchange1"的直接交换机 // 参数:交换机名称、类型、是否持久化、是否自动删除、额外属性 channel->declareExchange("exchange1", mymq::ExchangeType::DIRECT, true, false, tmp_map); // 4.2 声明一个持久化队列"queue1" // 参数:队列名称、是否持久化、是否排他、是否自动删除、额外属性 channel->declareQueue("queue1", true, false, false, tmp_map); // 4.3 声明一个持久化队列"queue2" channel->declareQueue("queue2", true, false, false, tmp_map); // 4.4 将队列"queue1"绑定到交换机"exchange1",绑定键为"queue1" // 参数:交换机名称、队列名称、绑定键 channel->queueBind("exchange1", "queue1", "queue1"); // 4.5 将队列"queue2"绑定到交换机"exchange1",绑定键为"news.music.#" // "#"是通配符,表示匹配多个单词 channel->queueBind("exchange1", "queue2", "news.music.#"); // 5. 使用std::bind创建回调函数适配器 // std::bind将回调函数cb与参数绑定,其中channel作为第一个参数固定传入 // std::placeholders::_1、_2、_3代表回调函数cb的consumer_tag、bp、body参数 auto functor = std::bind(cb, channel, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); // 6. 开始消费指定队列的消息 // 参数: // consumer1: 消费者标签,用于标识此消费者 // argv[1]: 队列名称,从命令行参数获取 // false: 是否自动确认消息,false表示需要手动确认(basicAck) // functor: 消息到达时的回调函数 channel->basicConsume("consumer1", argv[1], false, functor); // 7. 保持程序运行,等待消息 // 使用无限循环,每3秒休眠一次,避免CPU占用过高 while(1) { std::this_thread::sleep_for(std::chrono::seconds(3)); } // 8. 关闭信道(这里不会被执行,因为程序一直循环等待消息) conn->closeChannel(channel); return 0; }

编译还是和上面一样

2.2.测试

注意:每次测试之前都需要删除/data目录,这里面存储的是持久化的绑定信息,我们需要将它们删除

没有问题,接下来我们就进入我们的测试环节

首先我们先启动服务器

服务器已经运行起来了

我们先运行消费者客户端

./consume_client queue1

换一个终端

./consume_client queue2

换一个终端

./publish_client

运行之后,我们发现绑定了queue1的消费者收到了消息

但是绑定queue2的消费者没有收到消息

三.主题交换模式下的测试

3.1.生产者消费者代码编写

生产者客户端实现

#include "connection.hpp" int main() { // 1. 创建异步工作线程对象,用于处理网络IO mymq::AsyncWorker::ptr awp = std::make_shared<mymq::AsyncWorker>(); // 2. 建立与RabbitMQ服务器的连接 // 参数:服务器地址、端口号、异步工作线程 mymq::Connection::ptr conn = std::make_shared<mymq::Connection>("127.0.0.1", 8085, awp); // 3. 通过连接创建信道 mymq::Channel::ptr channel = conn->openChannel(); // 4. 声明交换机和队列,并建立绑定关系 // 使用空的属性映射(不设置额外参数) google::protobuf::Map<std::string, std::string> tmp_map; // 4.1 声明一个名为"exchange1"的主题交换机(ExchangeType::TOPIC) // 参数:交换机名称、类型、是否持久化、是否自动删除、额外属性 channel->declareExchange("exchange1", mymq::ExchangeType::TOPIC, true, false, tmp_map); // 4.2 声明一个持久化队列"queue1" // 参数:队列名称、是否持久化、是否排他、是否自动删除、额外属性 channel->declareQueue("queue1", true, false, false, tmp_map); // 4.3 声明一个持久化队列"queue2" channel->declareQueue("queue2", true, false, false, tmp_map); // 4.4 将队列"queue1"绑定到交换机"exchange1",绑定键为"queue1" // 参数:交换机名称、队列名称、绑定键 channel->queueBind("exchange1", "queue1", "queue1"); // 4.5 将队列"queue2"绑定到交换机"exchange1",绑定键为"news.music.#" // "#"是通配符,表示匹配多个单词 channel->queueBind("exchange1", "queue2", "news.music.#"); // 5. 发布消息到交换机 // 5.1 发送10条路由键为"news.music.pop"的消息 for (int i = 0; i < 10; i++) { mymq::BasicProperties bp; bp.set_id(mymq::UUIDHelper::uuid()); // 设置消息唯一ID bp.set_delivery_mode(mymq::DeliveryMode::DURABLE); // 设置消息持久化 bp.set_routing_key("news.music.pop"); // 设置路由键 // 发布消息:交换机名称、消息属性、消息内容 channel->basicPublish("exchange1", &bp, "Hello World-" + std::to_string(i)); } // 5.2 发送一条路由键为"news.music.sport"的消息 mymq::BasicProperties bp; bp.set_id(mymq::UUIDHelper::uuid()); bp.set_delivery_mode(mymq::DeliveryMode::DURABLE); bp.set_routing_key("news.music.sport"); channel->basicPublish("exchange1", &bp, "Hello Bite"); // 5.3 发送一条路由键为"news.sport"的消息 // 注意:修改了同一个bp对象的路由键,会覆盖之前的设置 bp.set_routing_key("news.sport"); channel->basicPublish("exchange1", &bp, "Hello chileme?"); // 6. 关闭信道 conn->closeChannel(channel); return 0; }

消费者客户端实现

我们创建一个consume_client.cc,然后把下面这些内容填写进去即可

#include "connection.hpp" #include <iostream> #include <thread> #include <chrono> #include <functional> // 消息消费回调函数 // 参数: // channel: 消息通道指针,用于发送确认消息等操作 // consumer_tag: 消费者标签,标识不同的消费者 // bp: 消息基本属性,包含消息ID、路由键等信息 // body: 消息体内容 void cb(mymq::Channel::ptr &channel, const std::string consumer_tag, const mymq::BasicProperties *bp, const std::string &body) { // 打印消费者信息和接收到的消息内容 std::cout << consumer_tag << "消费了消息:" << body << std::endl; // 发送消息确认,告诉RabbitMQ消息已被成功处理 // 参数:消息唯一ID channel->basicAck(bp->id()); } int main(int argc, char *argv[]) { // 检查命令行参数:需要指定要消费的队列名称 if (argc != 2) { std::cout << "使用方法: ./consume_client <队列名称>\n"; std::cout << "示例: ./consume_client queue1\n"; return -1; } // 1. 创建异步工作线程对象,用于处理网络IO和消息回调 mymq::AsyncWorker::ptr awp = std::make_shared<mymq::AsyncWorker>(); // 2. 建立与RabbitMQ服务器的连接 // 参数:服务器地址、端口号、异步工作线程 mymq::Connection::ptr conn = std::make_shared<mymq::Connection>("127.0.0.1", 8085, awp); // 3. 通过连接创建信道,信道是执行AMQP操作的通道 mymq::Channel::ptr channel = conn->openChannel(); // 4. 声明交换机和队列,并建立绑定关系 // 使用空的属性映射(不设置额外参数) google::protobuf::Map<std::string, std::string> tmp_map; // 4.1 声明一个名为"exchange1"的主题交换机(ExchangeType::TOPIC) // 参数:交换机名称、类型、是否持久化、是否自动删除、额外属性 channel->declareExchange("exchange1", mymq::ExchangeType::TOPIC, true, false, tmp_map); // 4.2 声明一个持久化队列"queue1" // 参数:队列名称、是否持久化、是否排他、是否自动删除、额外属性 channel->declareQueue("queue1", true, false, false, tmp_map); // 4.3 声明一个持久化队列"queue2" channel->declareQueue("queue2", true, false, false, tmp_map); // 4.4 将队列"queue1"绑定到交换机"exchange1",绑定键为"queue1" // 参数:交换机名称、队列名称、绑定键 channel->queueBind("exchange1", "queue1", "queue1"); // 4.5 将队列"queue2"绑定到交换机"exchange1",绑定键为"news.music.#" // "#"是通配符,表示匹配多个单词 channel->queueBind("exchange1", "queue2", "news.music.#"); // 5. 使用std::bind创建回调函数适配器 // std::bind将回调函数cb与参数绑定,其中channel作为第一个参数固定传入 // std::placeholders::_1、_2、_3代表回调函数cb的consumer_tag、bp、body参数 auto functor = std::bind(cb, channel, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); // 6. 开始消费指定队列的消息 // 参数: // consumer1: 消费者标签,用于标识此消费者 // argv[1]: 队列名称,从命令行参数获取 // false: 是否自动确认消息,false表示需要手动确认(basicAck) // functor: 消息到达时的回调函数 channel->basicConsume("consumer1", argv[1], false, functor); // 7. 保持程序运行,等待消息 // 使用无限循环,每3秒休眠一次,避免CPU占用过高 while(1) { std::this_thread::sleep_for(std::chrono::seconds(3)); } // 8. 关闭信道(这里不会被执行,因为程序一直循环等待消息) conn->closeChannel(channel); return 0; }

编译测试

我们可以先进行编译一下,

all: publish_client consume_client publish_client: publish_client.cc ../third/include/muduo/protobuf/codec.cc ../mqcommon/msg.pb.cc ../mqcommon/proto.pb.cc g++ $^ -o $@ -g -I ../third/include -L ../third/lib -lmuduo_net -lmuduo_base -lpthread -lprotobuf -lz -lsqlite3 consume_client: consume_client.cc ../third/include/muduo/protobuf/codec.cc ../mqcommon/msg.pb.cc ../mqcommon/proto.pb.cc g++ $^ -o $@ -g -I ../third/include -L ../third/lib -lmuduo_net -lmuduo_base -lpthread -lprotobuf -lz -lsqlite3 .PHONY: clean clean: rm -rf publish_client consume_client

3.2.测试

注意:每次测试之前都需要删除/data目录,这里面存储的是持久化的绑定信息,我们需要将它们删除

没有问题,接下来我们就进入我们的测试环节

首先我们先启动服务器

服务器已经运行起来了

我们先运行消费者客户端

./consume_client queue1

换一个终端

./consume_client queue2

换一个终端

./publish_client

运行之后,我们发现这个queue2的收到了消息

而绑定了queue1的客户端则没有任何反应

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/5 22:00:32

使用“TextIn智能文字识别产品”实现AI OCR智能识别方案,赋能企业数字化转型新时代

随着深度学习、大数据、人工智能、AI等技术领域的不断发展&#xff0c;机器学习是目前最火热的人工智能分支之一&#xff0c;是使用大量数据训练计算机程序&#xff0c;以实现智能决策、语音识别、图像处理等任务。各行各业都在积极探索这些技术的应用。特别是在深度学习领域&a…

作者头像 李华
网站建设 2026/3/7 11:49:06

HuggingFace Pipeline快速调用:零代码运行大模型生成token

HuggingFace Pipeline快速调用&#xff1a;零代码运行大模型生成token 在实验室里&#xff0c;一个研究生正为部署Llama3焦头烂额——CUDA版本不匹配、PyTorch编译报错、显存溢出……而隔壁工位的同事只用三行代码就跑通了GPT-2文本生成。这种反差背后&#xff0c;正是现代AI工…

作者头像 李华
网站建设 2026/3/9 22:47:15

YOLO系列模型统一训练平台:基于PyTorch-CUDA-v2.8构建

YOLO系列模型统一训练平台&#xff1a;基于PyTorch-CUDA-v2.8构建 在当前智能视觉应用爆发式增长的背景下&#xff0c;目标检测技术正以前所未有的速度渗透到自动驾驶、工业质检、安防监控等关键领域。YOLO&#xff08;You Only Look Once&#xff09;系列因其“单次前向传播即…

作者头像 李华
网站建设 2026/3/9 3:13:57

道路坑洞检测数据集介绍-2800张图片 智能交通监控系统 自动驾驶车辆感知 道路维护管理 移动巡检系统 移动巡检系统 保险理赔评估 城市基础设施数字化

&#x1f4e6;点击查看-已发布目标检测数据集合集&#xff08;持续更新&#xff09; 数据集名称图像数量应用方向博客链接&#x1f50c; 电网巡检检测数据集1600 张电力设备目标检测点击查看&#x1f525; 火焰 / 烟雾 / 人检测数据集10000张安防监控&#xff0c;多目标检测点…

作者头像 李华
网站建设 2026/3/8 11:29:31

强化学习笔记

基本概念 强化学习中涉及的基本概念&#xff1a; 环境 (Environment)&#xff1a;环境是智能体所处的外部系统&#xff0c;它负责产生当前的状态&#xff0c;接收智能体的动作并返回新的状态和对应的奖励。环境的作用相当于模拟现实中的条件和反应规则&#xff0c;智能体只能通…

作者头像 李华
网站建设 2026/3/4 5:41:33

揭秘要诀!AI应用架构师揭秘企业算力资源调度要诀

揭秘要诀&#xff01;AI应用架构师揭秘企业算力资源调度要诀 关键词&#xff1a;AI应用架构师、企业算力资源调度、资源分配、负载均衡、调度算法、算力优化、云计算 摘要&#xff1a;本文由AI应用架构师深入剖析企业算力资源调度的关键要诀。首先介绍算力资源调度在企业发展尤…

作者头像 李华