当前位置: 首页 > news >正文

学习gRPC (三)

测试gRPC例子

  • 编写proto文件
  • 实现服务端代码
  • 实现客户端代码

通过gRPC 已经编译并且安装好之后,就可以在源码目录下找到example 文件夹下来试用gRPC 提供的例子。

在这里我使用VS2022来打开仓库目录下example/cpp/helloworld目录
在这里插入图片描述

编写proto文件

下面是我改写的example/protos/helloworld.proto ,和相应的greeter_client.ccgreeter_server.cc两个文件。这里面定义了一个叫做Greeter的服务,同时这里尝试4种类型的方法。

  1. 简单 RPC ,客户端使用存根发送请求到服务器并等待响应返回,就像平常的函数调用一样。
  2. 服务器端流式 RPC , 客户端发送请求到服务器,拿到一个流去读取返回的消息序列。 客户端读取返回的流,直到里面没有任何消息。从例子中可以看出,通过在响应类型前插入 stream 关键字,可以指定一个服务器端的流方法。
  3. 客户端流式 RPC ,客户端写入一个消息序列并将其发送到服务器,同样也是使用流。一旦客户端完成写入消息,它等待服务器完成读取返回它的响应。通过在请求类型前指定 stream 关键字来指定一个客户端的流方法。
  4. 双向流式 RPC,双方使用读写流去发送一个消息序列。两个流独立操作,因此客户端和服务器可以以任意喜欢的顺序读写:比如,服务器可以在写入响应前等待接收所有的客户端消息,或者可以交替的读取和写入消息,或者其他读写的组合。 每个流中的消息顺序被预留。你可以通过在请求响应前加 stream 关键字去制定方法的类型。
syntax = "proto3";option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";package helloworld;// The greeting service definition.
service Greeter {// A simple RPC rpc SayHello (HelloRequest) returns (HelloReply) {}// A server-side streaming RPCrpc SayHelloStreamReply (HelloRequest) returns (stream HelloReply) {}// A client-side streaming RPC rpc StreamHelloReply (stream HelloRequest) returns (HelloReply) {}// A bidirectional streaming RPCrpc StreamHelloStreamReply (stream HelloRequest) returns (stream HelloReply) {}
}// The request message containing the user's name.
message HelloRequest {string name = 1;
}// The response message containing the greetings
message HelloReply {string message = 1;
}

当编辑完helloworld.proto文件之后,可以直接点击vs2022->生成->全部重新生成。此时VS会调用protocol buffer 编译器和gRPC C++ plugin生成4个客户端和服务端的文件,所有生成的文件在${projectDir}\out\build\${name}文件夹下。

如下方是我编写的手动生成这4个文件的批处理脚本

@echo offset fileName=temp
set currentPath=%~dp0%
set target=--cpp_out
set protocPath= "Your protoc path"
set pluginPath= "Your c++ plugin path"for %%I in (%*) do (for /f "tokens=1,2 delims=-/:" %%J in ("%%I%") do (if %%J==f (set fileName=%%K)if %%J==t (set target=%%K))
)if not exist "%currentPath%%fileName%" (echo file not existgoto:error
)
if %target%==python (set pluginPath= "Your python plugin path"set target=--python_out
)
if %target%==csharp (set pluginPath= "Your C# plugin path"set target=--csharp_out
)%protocPath% --grpc_out=%currentPath% --plugin=protoc-gen-grpc=%pluginPath% --proto_path=%currentPath% %fileName%
%protocPath% %target%=%currentPath% --proto_path=%currentPath% %fileName% 
:error
pause
exit

真正起作用编译出4个文件的代码是

%protocPath% --grpc_out=%currentPath% --plugin=protoc-gen-grpc=%pluginPath% --proto_path=%currentPath% %fileName%
%protocPath% %target%=%currentPath% --proto_path=%currentPath% %fileName% 

至此${projectDir}\out\build\${name}文件夹下会生成如下4个文件

  • helloworld.pb.h 消息类的头文件
  • helloworld.pb.cc 消息类的实现
  • helloworld.grpc.pb.h 服务类的头文件
  • helloworld.grpc.pb.cc 服务类的实现

同时里面还包含所有的填充、序列化和获取请求和响应消息类型的 protocol buffer 代码,和一个名为Greeter的类,这个类中包含了:

  • 方便客户端调用的存根
  • 需要服务端实现的虚接口

实现服务端代码

以下是greeter_server.cc

#include <iostream>
#include <memory>
#include <string>#include "absl/flags/flag.h"
#include "absl/flags/parse.h"
#include "absl/strings/str_format.h"#include <grpcpp/ext/proto_server_reflection_plugin.h>
#include <grpcpp/grpcpp.h>
#include <grpcpp/health_check_service_interface.h>#ifdef BAZEL_BUILD
#include "examples/protos/helloworld.grpc.pb.h"
#else
#include "helloworld.grpc.pb.h"
#endifusing grpc::Server;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::Status;
using grpc::ServerWriter;
using grpc::ServerReader;
using grpc::ServerReaderWriter;
using helloworld::Greeter;
using helloworld::HelloReply;
using helloworld::HelloRequest;using std::string;ABSL_FLAG(uint16_t, port, 50051, "Server port for the service");// Logic and data behind the server's behavior.
class GreeterServiceImpl final : public Greeter::Service
{Status SayHello(ServerContext* context, const HelloRequest* request, HelloReply* reply) override{std::cout << "--------" << __FUNCTION__ << "--------" << std::endl;string strName = request->name();reply->set_message("Hello : " + strName);std::cout << "--------" << __FUNCTION__ << "--------" << std::endl;return Status::OK;}Status SayHelloStreamReply(ServerContext* context, const HelloRequest* request, ServerWriter<HelloReply>* writer){std::cout << "--------" << __FUNCTION__ << "--------" << std::endl;string strName = request->name();HelloReply reply;reply.set_message("Hello " + strName);writer->Write(reply);for (unsigned int i = 0; i < 10; i++){reply.clear_message();reply.set_message("This is Server Reply : " + std::to_string(i));writer->Write(reply);}std::cout << "--------" << __FUNCTION__ << "--------" << std::endl;return Status::OK;}Status StreamHelloReply(ServerContext* context, ServerReader<HelloRequest>* reader, HelloReply* response){std::cout << "--------" << __FUNCTION__ << "--------" << std::endl;HelloRequest req;while (reader->Read(&req)){std::cout << "Server got what you said " << req.name() << std::endl;}response->set_message("Server got what you said " + req.name());std::cout << "--------" << __FUNCTION__ << "--------" << std::endl;return Status::OK;}Status StreamHelloStreamReply(ServerContext* context, ServerReaderWriter< HelloReply, HelloRequest>* stream){std::cout << "--------" << __FUNCTION__ << "--------" << std::endl;HelloRequest req;HelloReply reply;unsigned long uiCount = 0ul;while (stream->Read(&req)){std::cout << "Server got what you said " << req.name() << std::endl;reply.clear_message();reply.set_message("This is Server count " + std::to_string(uiCount++));stream->Write(reply);}std::cout << "--------" << __FUNCTION__ << "--------" << std::endl;return Status::OK;}
};void RunServer(uint16_t port) {std::string server_address = absl::StrFormat("0.0.0.0:%d", port);GreeterServiceImpl service;grpc::EnableDefaultHealthCheckService(true);grpc::reflection::InitProtoReflectionServerBuilderPlugin();ServerBuilder builder;// Listen on the given address without any authentication mechanism.builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());// Register "service" as the instance through which we'll communicate with// clients. In this case it corresponds to an *synchronous* service.builder.RegisterService(&service);// Finally assemble the server.std::unique_ptr<Server> server(builder.BuildAndStart());std::cout << "Server listening on " << server_address << std::endl;// Wait for the server to shutdown. Note that some other thread must be// responsible for shutting down the server for this call to ever return.server->Wait();
}int main(int argc, char** argv) {absl::ParseCommandLine(argc, argv);RunServer(absl::GetFlag(FLAGS_port));return 0;
}

可以看到,里面有两部分代码。一部分是真正实现服务接口内在逻辑的代码,逻辑都在GreeterServiceImpl 这个类中。另一部分是运行一个服务,并使它监听固定端口的代码,逻辑都在RunServer这个函数中。

实现客户端代码

以下是greeter_client.cc

#include <iostream>
#include <memory>
#include <string>
#include <chrono>
#include <thread>#include "absl/flags/flag.h"
#include "absl/flags/parse.h"#include <grpcpp/grpcpp.h>#ifdef BAZEL_BUILD
#include "examples/protos/helloworld.grpc.pb.h"
#else
#include "helloworld.grpc.pb.h"
#endifABSL_FLAG(std::string, target, "localhost:50051", "Server address");using grpc::Channel;
using grpc::ClientContext;
using grpc::Status;
using helloworld::Greeter;
using helloworld::HelloReply;
using helloworld::HelloRequest;
using std::thread;class GreeterClient {public:GreeterClient(std::shared_ptr<Channel> channel): stub_(Greeter::NewStub(channel)) {}// Assembles the client's payload, sends it and presents the response back// from the server.void SayHello(const std::string& user){std::cout << "--------" << __FUNCTION__ << "--------" << std::endl;// Data we are sending to the server.HelloRequest request;request.set_name(user);// Container for the data we expect from the server.HelloReply reply;// Context for the client. It could be used to convey extra information to// the server and/or tweak certain RPC behaviors.ClientContext context;// The actual RPC.Status status = stub_->SayHello(&context, request, &reply);// Act upon its status.if (status.ok()) {std::cout << "Server said " << reply.message() << std::endl;} else {status.error_message();std::cout << status.error_code() << ": " << status.error_message()<< std::endl;}std::cout << "--------" << __FUNCTION__ << "--------" << std::endl;}void SayHelloStreamReply(const std::string& user){std::cout << "--------" << __FUNCTION__ << "--------" << std::endl;// Data we are sending to the server.HelloRequest request;request.set_name(user);// Context for the client. It could be used to convey extra information to// the server and/or tweak certain RPC behaviors.ClientContext context;HelloReply reply;// The actual RPC.auto Reader = stub_->SayHelloStreamReply(&context, request);while (Reader->Read(&reply)){std::cout << reply.message() << std::endl;}if (!Reader->Finish().ok()){std::cout << Reader->Finish().error_code() << ": " << Reader->Finish().error_message()<< std::endl;std::cout <<  "RPC failed" << std::endl;}std::cout << "--------" << __FUNCTION__ << "--------" << std::endl;}void StreamHelloReply(const std::string& user){std::cout << "--------" << __FUNCTION__ << "--------" << std::endl;HelloReply reply;ClientContext context;auto Writer = stub_->StreamHelloReply(&context, &reply);for (unsigned int i = 0; i < 10; i++){// Data we are sending to the server.HelloRequest request;std::string strName = user + std::to_string(i);request.set_name(strName);Writer->Write(request);}Writer->WritesDone();if (!Writer->Finish().ok()){std::cout << Writer->Finish().error_code() << ": " << Writer->Finish().error_message()<< std::endl;std::cout << "RPC failed" << std::endl;}else{std::cout << reply.message() << std::endl;}std::cout << "--------" << __FUNCTION__ << "--------" << std::endl;}void StreamHelloStreamReply(const std::string& user){std::cout << "--------" << __FUNCTION__ << "--------" << std::endl;HelloReply reply;ClientContext context;std::shared_ptr< ::grpc::ClientReaderWriter< ::helloworld::HelloRequest, ::helloworld::HelloReply>> Stream = stub_->StreamHelloStreamReply(&context);thread t1([Stream, user]() {for (unsigned int i = 0; i < 20; i++){// Data we are sending to the server.HelloRequest request;std::string strName = user + std::to_string(i);request.set_name(strName);Stream->Write(request);}Stream->WritesDone();});while (Stream->Read(&reply)){std::cout << reply.message() << std::endl;}t1.join();if (!Stream->Finish().ok()){std::cout << Stream->Finish().error_code() << ": " << Stream->Finish().error_message()<< std::endl;std::cout << "RPC failed" << std::endl;}std::cout << "--------" << __FUNCTION__ << "--------" << std::endl;}private:std::unique_ptr<Greeter::Stub> stub_;
};int main(int argc, char** argv) {absl::ParseCommandLine(argc, argv);// Instantiate the client. It requires a channel, out of which the actual RPCs// are created. This channel models a connection to an endpoint specified by// the argument "--target=" which is the only expected argument.std::string target_str = absl::GetFlag(FLAGS_target);// We indicate that the channel isn't authenticated (use of// InsecureChannelCredentials()).GreeterClient greeter(grpc::CreateChannel(target_str, grpc::InsecureChannelCredentials()));std::string strName = "User";greeter.SayHello(strName);Sleep(500);greeter.SayHelloStreamReply(strName);Sleep(500);greeter.StreamHelloReply(strName);Sleep(500);greeter.StreamHelloStreamReply(strName);return 0;
}

客户端代码想要调用服务必须要使用到存根,所以我们可以在代码里看到std::unique_ptr<Greeter::Stub> stub_。这样我们在客户端调用时,就像是调用一个本地方法一样。

相关文章:

学习gRPC (三)

测试gRPC例子 编写proto文件实现服务端代码实现客户端代码 通过gRPC 已经编译并且安装好之后&#xff0c;就可以在源码目录下找到example 文件夹下来试用gRPC 提供的例子。 在这里我使用VS2022来打开仓库目录下example/cpp/helloworld目录 编写proto文件 下面是我改写的exa…...

【html】学习记录

1.在建立一个页面的时候不是打开软件就开始写代码&#xff0c;要先规划好页面的布局框架&#xff0c;不然思想会很混乱&#xff0c;如做个人简历&#xff0c;要分区分块&#xff0c;把每个区域的内容搞清楚。 2.html的很多标签看上去作用都是一样的&#xff0c;但是实际有很大不…...

2023年人工智能技术与智慧城市发展白皮书

人工智能与智慧城市是当前热门的话题和概念&#xff0c;通过将人工智能技术应用在城市管理和服务中&#xff0c;利用自动化、智能化和数据化的方式提高城市运行效率和人民生活质量&#xff0c;最终实现城市发展的智慧化&#xff0c;提升城市居民的幸福感。 AI技术在城市中的应…...

《Python入门到精通》条件控制 if 语句

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;小白零基础《Python入门到精通》 if 语句 1、四种语法格式1.1、if1.2、if else1.3、if elif else1.4、if 嵌套 2、…...

如何编写一个易于维护的考试系统源码

编写一个易于维护的考试系统源码对于开发人员来说非常重要。一个易于维护的系统可以使代码更易于理解、修改和扩展&#xff0c;从而提高开发效率和系统稳定性。 第一步&#xff1a;良好的项目结构 良好的项目结构是一个易于维护的源码的基础。可以按照模块、功能或层次等方式…...

day 2 |977.有序数组的平方、209.长度最小的子数组、59.螺旋矩阵II

目录&#xff1a; 解题及思路学习 977.有序数组的平方 https://leetcode.cn/problems/squares-of-a-sorted-array/submissions/ 给你一个按 非递减顺序 排序的整数数组 nums&#xff0c;返回 每个数字的平方 组成的新数组&#xff0c;要求也按 非递减顺序 排序。 示例 1&a…...

【力扣每日一题】2023.8.2 翻转卡片游戏

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 这道题不是什么翻转卡片游戏&#xff0c;这就是纯纯的文字游戏&#xff0c;要是能看懂题目那就是非常简单&#xff0c;接下来我就给大家分…...

IDEA设置中文 中文插件

IDEA设置中文 中文插件 首先进入idea File --> Setting --> Plugin 输入Chinese 搜索插件 选择下图插件进行install 安装完成后&#xff0c;重启idea即可...

Python——调用webdriver.Chrome() 报错

今天运行脚本&#xff0c;报错内容如下&#xff1a; collecting ... login_case.py:None (login_case.py) login_case.py:11: in <module> dr webdriver.Chrome() D:\Program Files (x86)\Python\Python39\Lib\site-packages\selenium\webdriver\chrome\webdriver.p…...

人工智能发展的五个主要技术方向是什么?

人工智能主要分支介绍 通讯、感知与行动是现代人工智能的三个关键能力&#xff0c;在这里我们将根据这些能力/应用对这三个技术领域进行介绍&#xff1a; 计算机视觉(CV) 自然语言处理(NLP) 在 NLP 领域中&#xff0c;将覆盖文本挖掘/分类、机器翻译和语音识别。 机器人 1、…...

机器学习知识经验分享之六:决策树

python语言用于深度学习较为广泛&#xff0c;R语言用于机器学习领域中的数据预测和数据处理算法较多&#xff0c;后续将更多分享机器学习数据预测相关知识的分享&#xff0c;有需要的朋友可持续关注&#xff0c;有疑问可以关注后私信留言。 目录 一、R语言介绍 二、R语言安装…...

回归预测 | MATLAB实现SO-CNN-GRU蛇群算法优化卷积门控循环单元多输入单输出回归预测

回归预测 | MATLAB实现SO-CNN-GRU蛇群算法优化卷积门控循环单元多输入单输出回归预测 目录 回归预测 | MATLAB实现SO-CNN-GRU蛇群算法优化卷积门控循环单元多输入单输出回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 MATLAB实现SO-CNN-GRU蛇群算法优化卷积门控循…...

309. 买卖股票的最佳时机含冷冻期

给定一个整数数组prices&#xff0c;其中第 prices[i] 表示第 i 天的股票价格 。​ 设计一个算法计算出最大利润。在满足以下约束条件下&#xff0c;你可以尽可能地完成更多的交易&#xff08;多次买卖一支股票&#xff09;: 卖出股票后&#xff0c;你无法在第二天买入股票 …...

P1119 灾后重建

题目背景 B 地区在地震过后&#xff0c;所有村庄都造成了一定的损毁&#xff0c;而这场地震却没对公路造成什么影响。但是在村庄重建好之前&#xff0c;所有与未重建完成的村庄的公路均无法通车。换句话说&#xff0c;只有连接着两个重建完成的村庄的公路才能通车&#xff0c;…...

USB采集卡如何打pts

一、使用采集卡提供的pts 二、手动打pts 1.usb采集设备pts的问题 2.采集卡驱动&#xff0c;UVC/UAC&#xff0c;ffmpeg的关系 3.如何自己打pts 4.音视频同步调优 5.NTP等联网调时工具带来的不同步问题 一、使用采集卡提供的pts 我们用使用pc摄像头和使用pc麦克风声卡里的方法&…...

机器学习实战13-超导体材料的临界温度预测与分析(决策树回归,梯度提升回归,随机森林回归和Bagging回归)

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下机器学习实战13-超导体材料的临界温度预测与分析(决策树回归,梯度提升回归,随机森林回归和Bagging回归)&#xff0c;这几天引爆网络的科技大新闻就是韩国科研团队宣称发现了室温超导材料-LK-99&#xff0c;这种材料…...

小研究 - 一种复杂微服务系统异常行为分析与定位算法(二)

针对极端学生化偏差&#xff08;&#xff25;&#xff58;&#xff54;&#xff52;&#xff45;&#xff4d;&#xff45; &#xff33;&#xff54;&#xff55;&#xff44;&#xff45;&#xff4e;&#xff54;&#xff49;&#xff5a;&#xff45;&#xff44; &#…...

Docker 安装 MySQL5.6

方法一、docker pull mysql 查找Docker Hub上的mysql镜像 #docker search mysql 这里我们拉取官方的镜像,标签为5.6 #docker pull mysql:5.6 &#xff08;第一次启动Docker-MySql主要是查看Docker里面MySQL的默认配置&#xff0c;数据位置&#xff0c;日志位置&#xff0c;配…...

vue组件跳层级时的事件处理 (事件的广播与派发)

相信大家一定用过elementui这个组件库&#xff0c;那么对里面的表单组件一定不陌生。 最常用的几个组件就是el-form&#xff0c;el-form-item&#xff0c;el-input&#xff0c;表单校验时的错误提示功能是交给el-form-item来实现的。当el-input填写时触发校验规则&#xff0c;…...

毫米波雷达 TI IWR6843 官方测试程序(Out Of Box Demo)

1.硬件准备 1.IWR6843AOP板子 2.两个USB转串口模块&#xff08;因为我的是自己做的板子&#xff0c;板子上没有集成USB转串口芯片&#xff09; 2.软件准备 1.最新版本的CCS&#xff0c;注意后缀没有THEIA https://www.ti.com/tool/CCSTUDIO?DCMPdsp_ccs_v4&HQSccs 2.最…...

浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)

✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义&#xff08;Task Definition&…...

如何在看板中体现优先级变化

在看板中有效体现优先级变化的关键措施包括&#xff1a;采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中&#xff0c;设置任务排序规则尤其重要&#xff0c;因为它让看板视觉上直观地体…...

全球首个30米分辨率湿地数据集(2000—2022)

数据简介 今天我们分享的数据是全球30米分辨率湿地数据集&#xff0c;包含8种湿地亚类&#xff0c;该数据以0.5X0.5的瓦片存储&#xff0c;我们整理了所有属于中国的瓦片名称与其对应省份&#xff0c;方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序

一、开发环境准备 ​​工具安装​​&#xff1a; 下载安装DevEco Studio 4.0&#xff08;支持HarmonyOS 5&#xff09;配置HarmonyOS SDK 5.0确保Node.js版本≥14 ​​项目初始化​​&#xff1a; ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)

设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile&#xff0c;新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包

文章目录 现象&#xff1a;mysql已经安装&#xff0c;但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时&#xff0c;可能是因为以下几个原因&#xff1a;1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计

随着大语言模型&#xff08;LLM&#xff09;参数规模的增长&#xff0c;推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长&#xff0c;而KV缓存的内存消耗可能高达数十GB&#xff08;例如Llama2-7B处理100K token时需50GB内存&a…...

动态 Web 开发技术入门篇

一、HTTP 协议核心 1.1 HTTP 基础 协议全称 &#xff1a;HyperText Transfer Protocol&#xff08;超文本传输协议&#xff09; 默认端口 &#xff1a;HTTP 使用 80 端口&#xff0c;HTTPS 使用 443 端口。 请求方法 &#xff1a; GET &#xff1a;用于获取资源&#xff0c;…...

深度学习水论文:mamba+图像增强

&#x1f9c0;当前视觉领域对高效长序列建模需求激增&#xff0c;对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模&#xff0c;以及动态计算优势&#xff0c;在图像质量提升和细节恢复方面有难以替代的作用。 &#x1f9c0;因此短时间内&#xff0c;就有不…...

[大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.

ollama官网: 下载 https://ollama.com/ 安装 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token数量为409622 16384 ollama命令说明 ollama serve #&#xff1a…...