[实现Rpc] 客户端 | Requestor | RpcCaller的设计实现

目录

Requestor类的实现

框架

完善

onResponse处理回复

完整代码

RpcCaller类的实现

1. 同步调用 call

2. 异步调用 call

3. 回调调用 call


Requestor类的实现

(1)主要功能:

  • 客户端发送请求的功能,进行请求描述
  • 对服务器响应的处理机制,并对返回信息 进行对应接收

(2)具体实现:

  • 意义针对客户端的每一条请求进行管理,以便于对请求对应的响应做出合适操作。
  • 对于客户端而言,其通常是主动发起请求服务的一方。然而,在多线程网络通信中,针对多个请求进行响应时可能会存在时序问题,导致无法保证一个线程发送的请求后接收到的响应就是针对这条请求的响应,这是非常危险的情况。
  • 异步IO挑战:类似于Muduo库这种异步IO网络通信库,通常IO操作都是异步的,即发送数据是将数据放入发送缓冲区,而何时发送由底层网络库协调,并且不提供recv接口,而是连接触发可读事件后,IO读取数据完成调用处理回调进行数据处理,因此在发送请求后无法直接等待该条请求的响应。

解决方案

  • 创建请求管理模块,通过给每个请求设定一个请求ID来解决上述问题。服务端响应时会标识出响应针对的是哪个请求(即响应信息包含请求ID)。
  • 客户端无论收到 哪条请求的响应,都将数据存储入hash_map中,以请求ID作为映射,并提供获取指定请求ID响应的阻塞接口。这样,只要知道自己的请求ID,就能准确获取到想要的响应。
  • 进一步优化:可以将每个请求封装描述,添加异步future控制或设置回调函数的方式,不仅支持阻塞获取响应,也能实现异步获取响应及 回调处理响应。

框架

namespace bitrpc{
namespace client
{//客户端 部分class Requestor{public:using ptr = std::shared_ptr<Requestor>;using RequestCallback = std::function<void(const BaseMessage::ptr&)>;using AsyncResponse = std::future<BaseMessage::ptr>;struct RequestDescribe{using ptr=std::shared_ptr<RequestDescribe>;//智能指针 管理};//请求 信息描述//之后 好调用 所需要的rsp函数//Dispatcher调用void onResponse(const BaseConnection::ptr &conn,BaseMessage::ptr &msg){}//异步发送bool send(const BaseConnection::ptr &conn, const BaseMessage::ptr &req, AsyncResponse &async_rsp){}//同步发送bool send(const BaseConnection::ptr &conn, const BaseMessage::ptr &req, BaseMessage::ptr &rsp) {}//回调发送bool send(const BaseConnection::ptr &conn, const BaseMessage::ptr &req, const RequestCallback &cb) {}private://对于 请求 描述进行CURD//增RequestDescribe::ptr newDescribe(const BaseMessage::ptr &req, RType rtype, const RequestCallback &cb = RequestCallback()) {}//查 ridRequestDescribe::ptr getDescribe(const std::string &rid){}//删void delDescribe(const std::string &rid){}private:std::mutex _mutex;std::unordered_map<std::string, RequestDescribe::ptr> _request_desc;};
}
}

完善

信息描述

struct RequestDescribe {using ptr = std::shared_ptr<RequestDescribe>;BaseMessage::ptr request;RType rtype;std::promise<BaseMessage::ptr> response;RequestCallback callback;};

对收到的响应 通过 uid ,对应上是哪个请求发出的

实现了上面的解决问题

void onResponse(const BaseConnection::ptr &conn, BaseMessage::ptr &msg){std::string rid = msg->rid();RequestDescribe::ptr rdp = getDescribe(rid);//根据先获取msg->rid() 来进行结果的调用if (rdp.get() == nullptr) {ELOG("收到响应 - %s,但是未找到对应的请求描述!", rid.c_str());return;}if (rdp->rtype == RType::REQ_ASYNC) {rdp->response.set_value(msg);//调用 不同的接口}else if (rdp->rtype == RType::REQ_CALLBACK){if (rdp->callback) rdp->callback(msg);}else {ELOG("请求类型未知!!");}delDescribe(rid);
}
onResponse处理回复
  • onResponse方法是对收到的消息进行处理的入口点。当收到服务器的响应时,该方法会被调用来匹配相应的请求描述(RequestDescribe),并通过请求类型(RType)来决定如何处理响应:
    • 如果是 异步请求(RType::REQ_ASYNC),则通过设置std::promise的值(response.set_value(msg))来完成对应的std::future,使得调用者可以通过未来对象获取响应。
    • 如果是带有回调的请求(RType::REQ_CALLBACK),则直接调用注册的回调函数(rdp->callback(msg))来处理响应。
    • 如果请求类型未知,则记录错误日志。

onResponse方法则是 对接收到的响应进行处理,


关于 promise set_value: C++11 异步操作 future类_文档学习

send方法负责构建和发送请求,

//异步操作
bool send(const BaseConnection::ptr &conn, const BaseMessage::ptr &req, AsyncResponse &async_rsp)
{RequestDescribe::ptr rdp = newDescribe(req, RType::REQ_ASYNC);if (rdp.get() == nullptr){ELOG("构造请求描述对象失败!");return false;}conn->send(req);async_rsp = rdp->response.get_future();return true;
}
//同步操作
bool send(const BaseConnection::ptr &conn, const BaseMessage::ptr &req, BaseMessage::ptr &rsp)
{AsyncResponse rsp_future;bool ret = send(conn, req, rsp_future);if (ret == false){return false;}rsp = rsp_future.get();return true;
}
//回调函数
bool send(const BaseConnection::ptr &conn, const BaseMessage::ptr &req, const RequestCallback &cb)
{RequestDescribe::ptr rdp = newDescribe(req, RType::REQ_CALLBACK, cb);if (rdp.get() == nullptr){ELOG("构造请求描述对象失败!");return false;}conn->send(req);//!!!!!!!!!!!!!!!!return true;
}

1.

前文回顾:[C++#28][多态] 两个条件 | 虚函数表 | 抽象类 | override 和 final | 重载 重写 重定义

Requestor类中的 三个重载send方法,这些方法用于通过指定的连接对象发送消息

同:

  • 基本参数:所有三个send方法都接受两个相同的基本参数:一个指向BaseConnection的智能指针conn(表示网络连接)和一个指向BaseMessage的智能指针req(表示要发送的消息)。
  • 错误处理:每个send方法在无法成功创建请求描述对象时,都会记录错误日志并返回false,指示操作失败。
  • 消息发送:无论哪种方式,最终都是通过调用conn->send(req)来执行实际的消息发送。

异:

  • send方法(有三个重载版本)用于通过网络连接conn发送请求消息req到服务器:
    • 第一个send方法接受一个AsyncResponse &async_rsp参数,用于异步发送请求并返回一个std::future对象,以便于后续获取响应。(不阻塞
    • 第二个send方法是同步的,它 等待直到接收到服务器的响应并将结果赋值给BaseMessage::ptr &rsp
    • 第三个send方法允许用户在发送请求时提供一个回调函数const RequestCallback &cb,当收到响应时会自动调用该回调进行处理。(send 后,就不管了,不会阻塞等待)

📒对比第一种和第三种方式:

  1. 结果获取方式
    • 第一种方法需调用者主动通过future.get()获取结果,可能导致阻塞。
    • 第三种方法响应到达时自动调用回调函数处理结果,无需主动获取。
  1. 编程模型
    • 第一种更接近同步编程风格,通过异步手段避免长时间阻塞。
    • 第三种是典型的异步编程模型,更适合处理并发任务和事件驱动架构。
  1. 灵活性与复杂性
    • 第一种方法直观但可能引入复杂的依赖关系管理。
    • 第三种方法灵活,尤其适合链式异步操作,但可能导致“回调地狱”,增加代码维护难度。

<id,请求 desc> CURD

private:// 对于 请求 描述进行CURD//增RequestDescribe::ptr newDescribe(const BaseMessage::ptr &req, RType rtype,const RequestCallback &cb = RequestCallback()){std::unique_lock<std::mutex> lock(_mutex);//加锁RequestDescribe::ptr rd = std::make_shared<RequestDescribe>();rd->request = req;rd->rtype = rtype;if (rtype == RType::REQ_CALLBACK && cb){rd->callback = cb;}_request_desc.insert(std::make_pair(req->GetId(), rd));//将id 和描述 进行对应return rd;}//查RequestDescribe::ptr getDescribe(const std::string &rid){std::unique_lock<std::mutex> lock(_mutex);auto it = _request_desc.find(rid);if (it == _request_desc.end()){return RequestDescribe::ptr();}return it->second;}//删void delDescribe(const std::string &rid){std::unique_lock<std::mutex> lock(_mutex);_request_desc.erase(rid);}

完整代码

#pragma once
#include "../common/net.hpp"
#include "../common/message.hpp"
#include <future> //异步操作
#include <functional> //1.灵活的函数使用 bind functionnamespace bitrpc{
namespace client
{//客户端 部分class Requestor{public:using ptr = std::shared_ptr<Requestor>;using RequestCallback = std::function<void(const BaseMessage::ptr&)>;using AsyncResponse = std::future<BaseMessage::ptr>;//异步处理信息struct RequestDescribe {using ptr = std::shared_ptr<RequestDescribe>;BaseMessage::ptr request;RType rtype;std::promise<BaseMessage::ptr> response;RequestCallback callback;};//请求 信息描述//之后 好调用 所需要的rsp函数//Dispatcher 给RSP_RPC回复调用的void onResponse(const BaseConnection::ptr &conn, BaseMessage::ptr &msg){std::string rid = msg->GetId();RequestDescribe::ptr rdp = getDescribe(rid);if (rdp.get() == nullptr) {ELOG("收到响应 - %s,但是未找到对应的请求描述!", rid.c_str());return;}if (rdp->rtype == RType::REQ_ASYNC) {rdp->response.set_value(msg);}else if (rdp->rtype == RType::REQ_CALLBACK){if (rdp->callback) rdp->callback(msg);}else {ELOG("请求类型未知!!");}delDescribe(rid);}
//!!!!!!!对收到 的回复请求 进行id存储//异步详可见demo中的 使用//异步操作bool send(const BaseConnection::ptr &conn, const BaseMessage::ptr &req, AsyncResponse &async_rsp){RequestDescribe::ptr rdp = newDescribe(req, RType::REQ_ASYNC);if (rdp.get() == nullptr){ELOG("构造请求描述对象失败!");return false;}conn->send(req);async_rsp = rdp->response.get_future();return true;}//同步操作bool send(const BaseConnection::ptr &conn, const BaseMessage::ptr &req, BaseMessage::ptr &rsp){AsyncResponse rsp_future;bool ret = send(conn, req, rsp_future);if (ret == false){return false;}rsp = rsp_future.get();return true;}//回调函数bool send(const BaseConnection::ptr &conn, const BaseMessage::ptr &req, const RequestCallback &cb){RequestDescribe::ptr rdp = newDescribe(req, RType::REQ_CALLBACK, cb);if (rdp.get() == nullptr){ELOG("构造请求描述对象失败!");return false;}conn->send(req);return true;}//private:// <id,请求 desc> CURD//增RequestDescribe::ptr newDescribe(const BaseMessage::ptr &req, RType rtype,const RequestCallback &cb = RequestCallback()){std::unique_lock<std::mutex> lock(_mutex);RequestDescribe::ptr rd = std::make_shared<RequestDescribe>();rd->request = req;rd->rtype = rtype;if (rtype == RType::REQ_CALLBACK && cb){rd->callback = cb;}_request_desc.insert(std::make_pair(req->GetId(), rd));//将id 和描述 进行对应return rd;}//查RequestDescribe::ptr getDescribe(const std::string &rid){std::unique_lock<std::mutex> lock(_mutex);auto it = _request_desc.find(rid);if (it == _request_desc.end()){return RequestDescribe::ptr();}return it->second;}//删void delDescribe(const std::string &rid){std::unique_lock<std::mutex> lock(_mutex);_request_desc.erase(rid);}private:std::mutex _mutex;std::unordered_map<std::string, RequestDescribe::ptr> _request_desc;};
}
}

RpcCaller类的实现

(Requestor 的处理 调用 RpcCaller)

(1)主要功能:

  • 给Requestor() 提供接口。

(2)具体实现:

  • 意义:向用户提供进行RPC调用的模块。这个模块相对简单,主要功能是向外提供几个RPC调用接口,内部实现向服务端发送请求并等待获取结果。
  • 调用方式
    1. 同步调用:发起调用后,等到收到响应结果后返回。
    2. 异步调用:发起调用后立即返回,可以在需要的时候获取结果。
    3. 回调调用:发起调用的同时设置结果的处理回调,收到响应后自动对结果进行回调处理。

❗❗❗❗ 

// requestor中的处理是针对BaseMessage进行处理的
// 用于在rpccaller中针对结果的处理是针对 RpcResponse里边的result进行的
#pragma once
#include "requestor.hpp"// request 有 rpc topic server
// 其中 rpc部分的 调用函数的 实现namespace bitrpc
{namespace client{class RpcCaller{public:using ptr = std::shared_ptr<RpcCaller>;using JsonAsyncResponse = std::future<Json::Value>;using JsonResponseCallback = std::function<void(const Json::Value &)>;RpcCaller(const Requestor::ptr &requestor) : _requestor(requestor) {}// requestor中的处理是针对BaseMessage进行处理的// 用于在rpccaller中针对结果的处理是针对 RpcResponse里边的result进行的//1.bool call(const BaseConnection::ptr &conn, const std::string &method,const Json::Value &params, Json::Value &result){DLOG("开始同步rpc调用...");// 1. 组织请求auto req_msg = MessageFactory::create<RpcRequest>();req_msg->SetId(UUID::uuid());req_msg->setMethod(method);req_msg->setParams(params);req_msg->SetMType(MType::REQ_RPC);BaseMessage::ptr rsp_msg;// 2. 发送请求bool ret = _requestor->send(conn, std::dynamic_pointer_cast<BaseMessage>(req_msg), rsp_msg);if (ret == false){ELOG("同步Rpc请求失败!");return false;}DLOG("收到响应,进行解析,获取结果!");// 3. 等待响应auto rpc_rsp_msg = std::dynamic_pointer_cast<RpcResponse>(rsp_msg);if (!rpc_rsp_msg){ELOG("rpc响应,向下类型转换失败!");return false;}if (rpc_rsp_msg->rcode() != RCode::RCODE_OK){ELOG("rpc请求出错:%s", errReason(rpc_rsp_msg->rcode()));return false;}result = rpc_rsp_msg->result();DLOG("结果设置完毕!");return true;}////2.bool call(const BaseConnection::ptr &conn, const std::string &method,const Json::Value &params, JsonAsyncResponse &result){// 向服务器发送异步回调请求,设置回调函数,回调函数中会传入一个promise对象,在回调函数中去堆promise设置数据auto req_msg = MessageFactory::create<RpcRequest>();req_msg->SetId(UUID::uuid());req_msg->SetMType(MType::REQ_RPC);req_msg->setMethod(method);req_msg->setParams(params);auto json_promise = std::make_shared<std::promise<Json::Value>>();result = json_promise->get_future();Requestor::RequestCallback cb = std::bind(&RpcCaller::Callback,this, json_promise, std::placeholders::_1);bool ret = _requestor->send(conn, std::dynamic_pointer_cast<BaseMessage>(req_msg), cb);if (ret == false){ELOG("异步Rpc请求失败!");return false;}return true;}//3.bool call(const BaseConnection::ptr &conn, const std::string &method,const Json::Value &params, const JsonResponseCallback &cb){auto req_msg = MessageFactory::create<RpcRequest>();req_msg->SetId(UUID::uuid());req_msg->SetMType(MType::REQ_RPC);req_msg->setMethod(method);req_msg->setParams(params);Requestor::RequestCallback req_cb = std::bind(&RpcCaller::Callback1,this, cb, std::placeholders::_1);bool ret = _requestor->send(conn, std::dynamic_pointer_cast<BaseMessage>(req_msg), req_cb);if (ret == false){ELOG("回调Rpc请求失败!");return false;}return true;}private:void Callback1(const JsonResponseCallback &cb, const BaseMessage::ptr &msg){auto rpc_rsp_msg = std::dynamic_pointer_cast<RpcResponse>(msg);if (!rpc_rsp_msg){ELOG("rpc响应,向下类型转换失败!");return;}if (rpc_rsp_msg->rcode() != RCode::RCODE_OK){ELOG("rpc回调请求出错:%s", errReason(rpc_rsp_msg->rcode()));return;}cb(rpc_rsp_msg->result());}void Callback(std::shared_ptr<std::promise<Json::Value>> result, const BaseMessage::ptr &msg){auto rpc_rsp_msg = std::dynamic_pointer_cast<RpcResponse>(msg);if (!rpc_rsp_msg){ELOG("rpc响应,向下类型转换失败!");return;}if (rpc_rsp_msg->rcode() != RCode::RCODE_OK){ELOG("rpc异步请求出错:%s", errReason(rpc_rsp_msg->rcode()));return;}result->set_value(rpc_rsp_msg->result());}private:Requestor::ptr _requestor;};}
}

RpcCaller类中 三个重载的call方法,这些方法提供了不同的方式来发起RPC调用,并处理从服务器返回的响应。每个call方法根据其参数和使用场景的不同,具有特定的功能和适用性:

1. 同步调用 call

  • 目的:同步地发起一个RPC请求,并等待直到收到服务器的响应。
  • 实现
    • 创建并配置一个RpcRequest消息。
    • 使用_requestor->send()发送请求,并阻塞等待响应。
    • 接收到响应后解析结果,并检查是否有错误发生。
    • 将结果设置到输出参数result中 返回给调用者。
  • 应用场景:适用于需要立即获取结果且可以接受当前线程被阻塞的情况。

2. 异步调用 call

  • 目的:异步地发起一个RPC请求,不阻塞当前线程,允许后续通过std::future机制获取结果。
  • 实现
    • 创建并配置一个RpcRequest消息。
    • 绑定一个回调函数Callback用于在接收到响应时设置std::promise的值。
    • 使用_requestor->send()发送请求,并立即返回(非阻塞)。
    • 结果 可以通过result.get()在未来某个时刻获取。
  • 应用场景:适合于那些希望避免阻塞主线程,但仍然需要明确获取结果的场景。

3. 回调调用 call

  • 目的:异步发起RPC请求并在接收到响应时自动调用用户提供的回调函数进行处理。
  • 实现
    • 创建并配置一个RpcRequest消息。
    • 绑定一个回调函数Callback1,该回调会在接收到响应时被调用,并进一步调用用户提供的回调函数处理结果。
    • 使用_requestor->send()发送请求,并立即返回(非阻塞)。
  • 应用场景:适用于不需要立即处理响应结果,到了 就回调 来处理响应数据的场景。

本节重点,通过 重载 来实现同步 回调 异步

  • 同步:阻塞 返回结果参数
  • 回调:非阻塞 到了就返回结果
  • 异步:非阻塞 .get()获取

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

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

相关文章

P2889 [USACO07NOV] Milking Time S

题目大意 有 N N N 个小时可以挤奶。其中有 m m m 个时间段可以给 Bessis 奶牛挤奶。第 i i i 个时间段为 s i s_i si​ ~ t i t_i ti​&#xff0c;可以获得 E f f i Eff_i Effi​ 滴奶。每次挤完奶后&#xff0c;人都要休息 R R R 小时。最后问&#xff0c;一共能挤出…

ONNX转RKNN的环境搭建和部署流程

将ONNX模型转换为RKNN模型的过程记录 工具准备 rknn-toolkit:https://github.com/rockchip-linux/rknn-toolkit rknn-toolkit2:https://github.com/airockchip/rknn-toolkit2 rknn_model_zoo:https://github.com/airockchip/rknn_model_zoo ultralytics_yolov8:https://github…

20250221 NLP

1.向量和嵌入 https://zhuanlan.zhihu.com/p/634237861 encoder的输入就是向量&#xff0c;提前嵌入为向量 二.多模态文本嵌入向量过程 1.文本预处理 文本tokenizer之前需要预处理吗&#xff1f; 是的&#xff0c;文本tokenizer之前通常需要对文本进行预处理。预处理步骤可…

C++基础知识学习记录—多态

1、函数覆盖 函数覆盖也被称为函数重写&#xff0c;类似于函数隐藏&#xff0c; 函数覆盖是多态的前提条件之一。 函数覆盖与函数隐藏的区别&#xff1a; ● 基类的被覆盖函数需要使用virtual关键字修饰&#xff0c;表示这个函数是一个虚函数 在Qt Creator中虚函数是斜体 虚…

GoFly框架中集成Bolt 和badfer两个Go语言嵌入式键值数据库

本插件集成了Bolt 和badfer两个纯Go实现的快速的嵌入式K/V数据库&#xff0c;方便开发时本地存储使用。插件集成Bolt 和badfer两个&#xff0c;如果确定使用其中一个&#xff0c;也可以把其中不用的一个删除&#xff0c;不删除也不会有任何影响。 插件使用说明 1.安装插件 到…

AWS - Redshift - 外部表读取 Parquet 文件中 timestamp 类型的数据

问题&#xff1a; 通过 Redshift Spectrum 功能可以读取 S3 中的文件&#xff0c;当读取 Parquet 文件时&#xff0c;如果列格式设置为 timestamp&#xff0c; 通过 psql 客户端读取会出现以下错误&#xff1a; testdb# select * from myspectrum_schema_0219.test_ns; ERROR…

Pretraining Language Models with Text-Attributed Heterogeneous Graphs

Pretraining Language Models with Text-Attributed Heterogeneous Graphs EMNLP 推荐指数&#xff1a;#paper/⭐⭐#​ 贡献&#xff1a; 我们研究了在更复杂的数据结构上预训练LM的问题&#xff0c;即&#xff0c;TAHG。与大多数只能从每个节点的文本描述中学习的PLM不同&…

重新求职刷题DAY18

1.513. 找树左下角的值 给定一个二叉树的 根节点 root&#xff0c;请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节点。 示例 1: 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 输入: root [2,1,3] 输出: 1思路&#xff1a; 这…

B站pwn教程笔记-2

这次是栈溢出基础。 栈基础知识 栈帧结构概览 看上图的高地址和低地址。arguments是子函数的形参。蓝色的是上一个栈的ebp值&#xff0c;用于在子函数执行完毕之后&#xff0c;返回到正确的ebp. heap的占的内存大大的超过stack。 下面看看调用栈的详细过程。 一个函数都是以…

Qt中C++与QML交互从原理、方法与实践陷阱深度解析

在我们使用Qt开发中&#xff0c;现在以及普遍通过 C 与 QML 的交互&#xff0c;将 C 的强大功能与 QML 的界面设计优势相结合&#xff0c;既保证了应用程序的性能和稳定性&#xff0c;又能快速实现美观、易用的用户界面。接下来专门讲下C与QML交互原理、方法与实践中的一些陷阱…

JavaScript获取DOM元素语法总结(getElementsByName()、querySelector()、querySelectorAll())

文章目录 JavaScript DOM 元素获取语法总结关键点简介方法概述详细报告引言DOM 元素获取方法1. getElementById()&#xff08;弃用&#xff09;2. getElementsByClassName()&#xff08;弃用&#xff09;3. getElementsByTagName()&#xff08;弃用&#xff09;4. getElementsB…

tableau之人口金字塔、漏斗图、箱线图

一、人口金字塔 人口金字塔在本质上就是成对的条形图 人口金字塔是一种特殊的旋风图 1、数据处理 对异常数据进行处理 2、创建人口金字塔图 将年龄进行分桶 将男女人数数据隔离开 分别绘制两个条形图 双击男性条形图底部&#xff0c;将数据进行翻转&#xff08;倒序&a…

首次使用WordPress建站的经验分享(一)

之前用过几种内容管理系统(CMS),如:dedeCMS、phpCMS、aspCMS,主要是为了前端独立建站,达到预期的效果,还是需要一定的代码基础的,至少要有HTML、Css、Jquery基础。 据说WordPress 是全球最流行的内容管理系统CMS,从现在开始记录一下使用WordPress 独立建站的步骤 选购…

【Viewer.js】vue3封装图片查看器

效果图 需求 点击图片放大可关闭放大的 图片 下载 cnpm in viewerjs状态管理方法 stores/imgSeeStore.js import { defineStore } from pinia export const imgSeeStore defineStore(imgSeeStore, {state: () > ({showImgSee: false,ImgUrl: ,}),getters: {},actions: {…

人工智能 阿里云算力服务器的使用

获取免费的阿里云服务器 阿里云免费使用地址&#xff1a; https://free.aliyun.com/ 选择 人工智能平台 PAI 选择交互式建模 再选建立实例。 选择对应的GPU 和镜像&#xff0c;点击确认。 注意&#xff1a;250个小时&#xff0c;用的时候开启&#xff0c;不用的时候关闭&…

mysql将表导出为sql文件

使用mysqldump命令 mysqldump是MySQL提供的一个命令行工具&#xff0c;用于导出数据库或表的结构和数据。要将表导出为SQL文件&#xff0c;可以使用以下命令&#xff1a; mysqldump -uroot -p123456 database_name table_name > output_file.sql

用HTML5+CSS+JavaScript实现新奇挂钟动画

用HTML5+CSS+JavaScript实现新奇挂钟动画 引言 在技术博客中,如何吸引粉丝并保持他们的关注?除了干货内容,独特的视觉效果也是关键。今天,我们将通过HTML5、CSS和JavaScript实现一个新奇挂钟动画,并将其嵌入到你的网站中。这个动画不仅能让你的网站脱颖而出,还能展示你的…

大语言模型(LLM)微调技术笔记

图1&#xff1a;大模型进化树2 大模型微调 在预训练后&#xff0c;大模型可以获得解决各种任务的通用能力。然而&#xff0c;越来越多的研究表明&#xff0c;大语言模型的能力可以根据特定目标进一步调整。 这就是微调技术&#xff0c;目前主要有两种微调大模型的方法1&…

AI汽车新风向:「死磕」AI底盘,引爆线控底盘新增长拐点

2025开年&#xff0c;DeepSeek火爆出圈&#xff0c;包括吉利、东风汽车、上汽、广汽、长城、长安、比亚迪等车企相继官宣接入&#xff0c;掀起了“AI定义汽车”浪潮。 而这股最火的AI汽车热潮&#xff0c;除了深度赋能智能座舱、智能驾驶等AI竞争更白热化的细分场景&#xff0…

硬件学习笔记--46 电能表影响量试验梳理

目录 1.电流和电压电路中的谐波影响试验 1&#xff09;电流和电压电路中谐波——第5次谐波试验 2&#xff09;电流和电压电路中谐波——方顶波波形试验 3&#xff09;​​​​​​​电流和电压电路中谐波——尖顶波波形试验 4&#xff09;​​​​​​​电流和电压电路中谐…