brpc 安装及使用
介绍
brpc(Baidu Remote Procedure Call)是百度开源的一个高性能、通用的 RPC(远程过程调用)框架,其目标是让使用者能轻松构建高并发、分布式的应用程序。以下从多个方面详细介绍brpc:
核心特性
- 高性能
- 多线程并发处理:支持多线程并发处理请求,可充分利用多核 CPU 的性能,提高系统的并发处理能力,轻松应对高并发场景。
- 异步 I/O:采用异步 I/O 模型,避免了传统同步 I/O 中线程阻塞的问题,使得线程在等待 I/O 操作完成时可以处理其他任务,进一步提升了系统的整体性能。
- 易用性
- 类函数调用的使用方式:使用 brpc 时,调用远程服务就像调用本地函数一样简单,开发者无需关心底层的网络通信细节,降低了开发难度。
- 自动重试与超时机制:框架内置了自动重试和超时机制,当请求失败时会自动进行重试,同时可以设置合理的超时时间,避免长时间等待,提高系统的健壮性和可靠性。
应用场景
- 分布式系统:在大规模的分布式系统中,不同服务之间需要进行远程调用,brpc 可以作为服务间通信的桥梁,提供高效、稳定的通信服务。例如,在微服务架构中,各个微服务之间可以使用 brpc 进行通信,实现服务的解耦和独立部署。
- 高性能计算:对于需要处理大量数据和高并发请求的高性能计算场景,brpc 的高性能特性可以充分发挥作用,提高系统的处理能力和响应速度。比如,在大数据处理、人工智能等领域,brpc 可以用于数据的传输和处理。
- 云计算:在云计算环境中,不同的云服务之间需要进行交互,brpc 可以提供可靠的远程调用服务,确保云服务的高效运行。例如,在云存储、云数据库等服务中,brpc 可以用于客户端与服务端之间的通信。
安装
sudo apt-get install -y git g++ make libssl-dev libprotobuf-dev libprotoc-dev protobuf-compiler libleveldb-dev
git clone https://github.com/apache/brpc.git
cd brpc/
mkdir build && cd build
cmake -DCMAKE_INSTALL_PREFIX=/usr .. && cmake --build . -j6
make && sudo make install
类与接口介绍
日志输出类与接口
namespace logging
{enum LoggingDestination{LOG_TO_NONE = 0 //表示不输出日志到任何目标(禁用日志功能)};struct BUTIL_EXPORT LoggingSettings{LoggingSettings();LoggingDestination logging_dest;};bool InitLogging(const LoggingSettings &settings);
}
protobuf 类与接口
namespace google
{namespace protobuf{class PROTOBUF_EXPORT Closure{public:Closure() {}virtual ~Closure();virtual void Run() = 0;};inline Closure *NewCallback(void (*function)());class PROTOBUF_EXPORT RpcController{bool Failed();std::string ErrorText();}}
}
回调机制
-
Closure
是异步 RPC 的完成通知载体,NewCallback
为其提供快速创建的辅助函数。 -
RpcController
通过Failed()
和ErrorText()
提供回调中可能需要的错误信息。
1. Closure
类
作用:定义了一个通用的、可扩展的回调操作,用于异步操作完成后的通知。子类必须实现 Run()
方法,定义具体的回调逻辑。
核心方法
方法 | 说明 |
---|---|
| 回调执行入口,由子类实现具体逻辑 |
| 虚析构函数,确保子类对象正确释放 |
设计意图
-
解耦异步操作与回调逻辑:允许用户自定义回调行为(如释放资源、触发事件等)。
-
与 Protobuf RPC 集成:广泛用于 RPC 完成后的异步通知。
示例用法
class MyCallback : public google::protobuf::Closure {
public:void Run() override {std::cout << "Callback executed!" << std::endl;delete this; // 自管理内存}
};
// 使用
google::protobuf::Closure* callback = new MyCallback();
callback->Run(); // 输出 "Callback executed!"
2. NewCallback
函数
作用:将普通函数(无参数、无返回值)包装为 Closure
对象。避免手动子类化,简化一次性回调的创建。
示例
void OnRpcDone() {std::cout << "RPC finished!" << std::endl;
}// 创建回调
google::protobuf::Closure* callback = google::protobuf::NewCallback(&OnRpcDone);
callback->Run(); // 输出 "RPC finished!"
delete callback; // 需手动释放
3. RpcController
类
作用:提供 RPC 执行过程中的错误处理和状态查询。
核心方法
方法 | 说明 |
---|---|
| 检查 RPC 是否失败 |
| 获取错误描述信息 |
典型用途
brpc::Controller cntl; // brpc 的实现类
MyService_Stub stub(&channel);
MyRequest request;
MyResponse response;// 发起异步 RPC
stub.MyMethod(&cntl, &request, &response, NewCallback(&OnRpcDone));
if (cntl.Failed()) {std::cerr << "RPC failed: " << cntl.ErrorText() << std::endl;
}
服务端类与接口
namespace brpc
{struct ServerOptions{// 无数据传输,则指定时间后关闭连接int idle_timeout_sec; // Default: -1 (disabled)int num_threads; // Default: #cpu-cores//....};enum ServiceOwnership {// 添加服务失败时,服务器将负责删除服务对象SERVER_OWNS_SERVICE,// 添加服务失败时,服务器也不会删除服务对象SERVER_DOESNT_OWN_SERVICE};class Server{int AddService(google::protobuf::Service *service,ServiceOwnership ownership);int Start(int port, const ServerOptions *opt);int Stop(int closewait_ms /*not used anymore*/);int Join();// 休眠直到 ctrl+c 按下,或者 stop 和 join 服务器void RunUntilAskedToQuit();};class ClosureGuard{explicit ClosureGuard(google::protobuf::Closure *done);~ClosureGuard(){if (_done)_done->Run();}};class HttpHeader{void set_content_type(const std::string &type)const std::string *GetHeader(const std::string &key) void SetHeader(const std::string &key,const std::string &value);const URI &uri() const { return _uri; }HttpMethod method() const { return _method; }void set_method(const HttpMethod method) int status_code() void set_status_code(int status_code);};class Controller : public google::protobuf::RpcController{void set_timeout_ms(int64_t timeout_ms);void set_max_retry(int max_retry);google::protobuf::Message *response();HttpHeader &http_response();HttpHeader &http_request();bool Failed();std::string ErrorText();using AfterRpcRespFnType = std::function<void(Controller *cntl,const google::protobuf::Message *req,const google::protobuf::Message *res)>;void set_after_rpc_resp_fn(AfterRpcRespFnType &&fn)};
}
1. ServerOptions
结构体
作用:配置 brpc 服务器的核心参数,通过 Server::Start() 控制服务器行为。
关键字段
-
idle_timeout_sec:
空闲连接超时时间(秒),默认-1
(不启用),例如设为30
表示 30 秒无数据则关闭连接。 -
num_threads:
工作线程数,默认CPU核心数-1
。高并发场景可适当增加,但需避免线程过多导致上下文切换开销。
2. ServiceOwnership
枚举
作用:控制服务对象的生命周期管理权限。
枚举值
-
SERVER_OWNS_SERVICE:
服务器负责删除服务对象(防止内存泄漏)。 -
SERVER_DOESNT_OWN_SERVICE:
用户自行管理服务对象生命周期(需手动释放)。
典型场景
MyService *service = new MyService;
server.AddService(service, SERVER_OWNS_SERVICE); // 服务器自动管理
server.AddService(service, SERVER_DOESNT_OWN_SERVICE); // 用户需手动 delete
3. Server
类
核心方法
方法 | 作用 | 参数说明 |
---|---|---|
| 注册 Protobuf 服务 |
|
| 启动服务器 |
|
| 停止服务器(非阻塞) |
|
| 等待服务器完全停止 | 需在 |
| 阻塞直到收到终止信号 | 替代手动 |
工作流程
brpc::Server server;
MyService service;
server.AddService(&service, brpc::SERVER_OWNS_SERVICE);brpc::ServerOptions options;
options.idle_timeout_sec = 30;
server.Start(8000, &options);
server.RunUntilAskedToQuit(); // 阻塞运行
4. ClosureGuard
类
作用:RAII 封装 Protobuf Closure
,确保析构时自动调用 done->Run()
,避免回调遗漏。
典型用法
void MyRpcMethod(..., google::protobuf::Closure *done)
{brpc::ClosureGuard done_guard(done); // 异常安全if (error){cntl->SetFailed("Error");return; // done_guard 析构时自动调用 done->Run()}// 正常处理...
}
5. HttpHeader
类
作用:管理 HTTP 请求/响应的头部信息,提供便捷的键值操作。
核心方法
方法 | 作用 |
---|---|
| 设置 |
| 获取指定头部值 |
| 设置自定义头部 |
| 获取请求 URI(路径、查询参数等) |
| 获取 HTTP 方法(GET/POST 等) |
示例
brpc::Controller cntl;
cntl.http_request().set_method(brpc::HTTP_METHOD_POST);
cntl.http_response().set_content_type("text/plain");
6. Controller
类
继承自 google::protobuf::RpcController
,扩展了 brpc 特有功能。
核心功能
方法 | 作用 |
---|---|
set_timeout_ms() | 设置 RPC 超时时间(毫秒) |
set_max_retry() | 设置最大重试次数 |
http_request() /http_response() | 访问 HTTP 头部 |
set_after_rpc_resp_fn() | 设置 RPC 完成后的回调(用于日志、统计等) |
典型流程
brpc::Controller cntl;
cntl.set_timeout_ms(5000); // 5秒超时
MyService_Stub stub(&channel);
MyRequest request;
MyResponse response;stub.MyMethod(&cntl, &request, &response, nullptr);
if (cntl.Failed()) {LOG(ERROR) << "RPC failed: " << cntl.ErrorText();
}
客户端类与接口
namespace brpc
{struct ChannelOptions{// 请求连接超时时间int32_t connect_timeout_ms; // Default: 200 (milliseconds)// rpc 请求超时时间int32_t timeout_ms; // Default: 500 (milliseconds)// 最大重试次数int max_retry; // Default: 3// 序列化协议类型 options.protocol = "baidu_std";AdaptiveProtocolType protocol;//....};class Channel : public ChannelBase{// 初始化接口,成功返回 0;int Init(const char *server_addr_and_port,const ChannelOptions *options);};
}
1. ChannelOptions
结构体
作用:用于配置 Channel
(RPC 客户端通道)的核心参数,控制连接和请求行为。
核心参数
参数 | 类型 | 默认值 | 说明 |
---|---|---|---|
|
| 200 ms | 连接超时时间:建立 TCP 连接的最长等待时间。 |
|
| 500 ms | 请求超时时间:RPC 调用的最长等待时间(从发送到接收响应)。 |
|
| 3 | 最大重试次数:连接或请求失败时的自动重试次数。 |
|
| - | 协议类型:如 |
2. Channel
类
作用:管理与服务端的通信通道,支持同步/异步调用。
核心方法
方法 | 说明 |
---|---|
| 初始化通道,连接指定的服务端地址。 |
示例
brpc::Channel channel;
brpc::ChannelOptions options;
options.timeout_ms = 1000; // 设置请求超时为 1 秒
options.max_retry = 1; // 禁用重试if (channel.Init("127.0.0.1:8000", &options) != 0) {// 处理初始化失败
}
使用
创建 proto 文件 - main.proto
syntax="proto3";
package example;
option cc_generic_services = true;// 定义 Echo 方法请求参数结构
message EchoRequest
{string message=1;
};
// 定义 Echo 方法响应参数结构
message EchoResponse
{string message=1;
};
// 定义 RPC 远端方法
service EchoService
{rpc Echo(EchoRequest) returns (EchoResponse);
};
protoc --cpp_out=./ main.proto
创建服务端源码 - server.cpp
#include <iostream>
#include <brpc/server.h>
#include <butil/logging.h>
#include "main.pb.h"
// 继承EchoService创建一个子类,并实现rpc调用的业务功能
class EchoServiceImpl : public example::EchoService
{
public:void Echo(google::protobuf::RpcController *controller,const example::EchoRequest *request, example::EchoResponse *response, google::protobuf::Closure *done){brpc::ClosureGuard guard(done);std::cout << "收到消息:" << request->message() << std::endl;std::string str = "这是响应--" + request->message();response->set_message(str);// done->Run(); 由于使用了ClosureGuard,异步完成时就不需要手动调用Run函数}
};
int main()
{// 关闭brpc的默认日志输出logging::LoggingSettings settings;settings.logging_dest = logging::LoggingDestination::LOG_TO_NONE;logging::InitLogging(settings);// 构造服务器对象brpc::Server server;// 向服务器对象添加EchoService服务EchoServiceImpl echo_service;int ret = server.AddService(&echo_service, brpc::ServiceOwnership::SERVER_OWNS_SERVICE);if (ret == -1){std::cout << "添加Rpc服务失败!\n";return -1;}// 启动服务器brpc::ServerOptions options;options.idle_timeout_sec = -1; // 连接空闲超时时间,超时后连接被关闭,-1为一直连接options.num_threads = 1; // io线程数量ret = server.Start(8080, &options);if (ret == -1){std::cout << "启动服务器失败!\n";return -1;}server.RunUntilAskedToQuit(); // 修改等待运行结束return 0;
}
创建客户端源码 - client.cpp
#include <iostream>
#include <thread>
#include <brpc/channel.h>
#include "main.pb.h"
#include <memory>
void callback(brpc::Controller *cntl, example::EchoResponse *response)
{std::unique_ptr<brpc::Controller> cntl_guard(cntl);std::unique_ptr<example::EchoResponse> rsp_guard(response);if (cntl->Failed() == true){std::cout << "Rpc调用失败:" << cntl->ErrorText() << std::endl;return;}std::cout << "收到响应: " << response->message() << std::endl;
}
int main()
{// 构造Channel信道,连接服务器brpc::ChannelOptions options;options.connect_timeout_ms = -1; // 连接等待超时时间,-1表示一直等待options.timeout_ms = -1; // rpc请求等待超时时间,-1表示一直等待options.max_retry = 3; // 请求重试次数options.protocol = "baidu_std"; // 序列化协议,默认使用baidu_stdbrpc::Channel channel;int ret = channel.Init("127.0.0.1:8080", &options);if (ret == -1){std::cout << "初始化信道失败!\n";return -1;}// 构造EchoService_Stub对象,用于进行rpc调用example::EchoService_Stub stub(&channel);// 进行rpc调用example::EchoRequest req;req.set_message("hello world!");brpc::Controller *cntl = new brpc::Controller();example::EchoResponse *rsp = new example::EchoResponse();// 1.同步调用stub.Echo(cntl, &req, rsp, nullptr);if (cntl->Failed() == true){std::cout << "Rpc调用失败:" << cntl->ErrorText() << std::endl;return -1;}std::cout << "收到响应: " << rsp->message() << std::endl;delete cntl;delete rsp;// 2.异步调用// auto closure = google::protobuf::NewCallback(callback,cntl,rsp);// stub.Echo(cntl, &req, rsp, closure);// std::cout << "异步调用结束!\n";// std::this_thread::sleep_for(std::chrono::seconds(3));return 0;
}
all:server client
server:server.cc main.pb.ccg++ -o $@ $^ -std=c++17 -lbrpc -lgflags -lssl -lcrypto -lprotobuf -lleveldb
client:client.cc main.pb.ccg++ -o $@ $^ -std=c++17 -lbrpc -lgflags -lssl -lcrypto -lprotobuf -lleveldb
二次封装
- rpc 调用这里的封装,因为不同的服务调用使用的是不同的 Stub,这个封装起来的意义不大,因此我们只需要封装通信所需的 Channel 管理即可,这样当需要进行什么样的服务调用的时候,只需要通过服务名称获取对应的 channel,然后实例化 Stub 进行调用即可。
- 封装 Channel 的管理,每个不同的服务可能都会有多个主机提供服务,因此一个服务可能会对应多个 Channel,需要将其管理起来,并提供获取指定服务 channel 的接口。进行 rpc 调用时,获取 channel,目前以 RR 轮转的策略选择 channel。
- 提供进行服务声明的接口,因为在整个系统中,提供的服务有很多,但是当前可能并不一定会用到所有的服务,因此通过声明来告诉模块哪些服务是自己关心的,需要建立连接管理起来,没有添加声明的服务即使上线也不需要进行连接的建立。
- 提供服务上线时的处理接口,也就是新增一个指定服务的 channel。
- 提供服务下线时的处理接口,也就是删除指定服务下的指定 channel。
#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <mutex>
#include "logger.hpp"
#include <brpc/channel.h>// 封装单个服务的信道管理类
class ServiceChannel
{
public:using ptr = std::shared_ptr<ServiceChannel>;using ChannelPtr = std::shared_ptr<brpc::Channel>;ServiceChannel(const std::string &name): _service_name(name), _index(0){}// 服务上线了一个节点,则调用append新增信道void append(const std::string &host){// 构造Channel信道,连接服务器brpc::ChannelOptions options;options.connect_timeout_ms = -1; // 连接等待超时时间,-1表示一直等待options.timeout_ms = -1; // rpc请求等待超时时间,-1表示一直等待options.max_retry = 3; // 请求重试次数options.protocol = "baidu_std"; // 序列化协议,默认使用baidu_stdauto channel = std::make_shared<brpc::Channel>();int ret = channel->Init(host.c_str(), &options);if (ret == -1){LOG_ERROR("初始化{}-{}信道失败!", _service_name, host);return;}std::unique_lock<std::mutex> lock(_mutex);_channels.push_back(channel);_hosts[host] = channel;}// 服务下线了一个节点,则调用remove释放信道void remove(const std::string &host){std::unique_lock<std::mutex> lock(_mutex);auto it = _hosts.find(host);if (it == _hosts.end()){LOG_WARN("删除{}-{}节点信道时,没有找到信道信息!", _service_name, host);return;}for (auto vit = _channels.begin(); vit != _channels.end(); vit++){if (*vit == it->second){_channels.erase(vit);break;}}_hosts.erase(it);}// 通过RR轮转策略,获取一个Channel用于发起对应服务的Rpc调用ChannelPtr choose(){std::unique_lock<std::mutex> lock(_mutex);if (_channels.size() == 0){LOG_ERROR("当前没有能够提供{}服务的节点!", _service_name);return ChannelPtr();}int32_t index = _index++ % _channels.size();return _channels[index];}private:std::mutex _mutex;int32_t _index; // 当前轮转下标的计数器std::string _service_name; // 服务名称std::vector<ChannelPtr> _channels; // 当前服务对应的信道集合std::unordered_map<std::string, ChannelPtr> _hosts; // 主机地址与信道的映射
};// 总体的服务信道管理类
class ServiceManager
{
public:using ptr = std::shared_ptr<ServiceManager>;// 获取指定服务的节点信道ServiceChannel::ChannelPtr choose(const std::string &service_name){std::unique_lock<std::mutex> lock(_mutex);auto it = _services.find(service_name);if (it == _services.end()){LOG_ERROR("当前没有能够提供{}服务的节点!", service_name);return ServiceChannel::ChannelPtr();}return it->second->choose();}// 先声明我关心哪些服务的上下线,不关心的则不需要管理void declared(const std::string &service_name){std::unique_lock<std::mutex> lock(_mutex);_follow_services.insert(service_name);}// 服务上线时调用的回调接口,将服务节点管理起来void onServiceOnline(const std::string &service_instance, const std::string &host){std::string service_name = getServiceName(service_instance);ServiceChannel::ptr service;{std::unique_lock<std::mutex> lock(_mutex);auto fit = _follow_services.find(service_name);if (fit == _follow_services.end()){LOG_DEBUG("{}-{}服务上线了,但是当前并不关心!", service_name, host);return;}// 先获取管理对象,没有则创建,有则添加节点auto sit = _services.find(service_name);if (sit == _services.end()){service = std::make_shared<ServiceChannel>(service_name);_services[service_name] = service;}elseservice = sit->second;}if (!service){LOG_ERROR("新增{}服务管理节点失败!", service_name);return;}service->append(host);LOG_DEBUG("{}-{} 服务上线新节点,进行添加管理!", service_name, host);}// 服务下线时调用的回调接口,从相应的服务节点删除信道void onServiceOffline(const std::string &service_instance, const std::string &host){std::string service_name = getServiceName(service_instance);ServiceChannel::ptr service;{std::unique_lock<std::mutex> lock(_mutex);auto fit = _follow_services.find(service_name);if (fit == _follow_services.end()){LOG_DEBUG("{}-{}服务下线了,但是当前并不关心!", service_name, host);return;}// 先获取管理对象,有则删除节点信道auto sit = _services.find(service_name);if (sit == _services.end()){LOG_WARN("删除{}服务节点时,没有找到管理对象", service_name);return;}elseservice = sit->second;}service->remove(host);LOG_DEBUG("{}-{} 服务下线节点,进行删除管理!", service_name, host);}private:std::string getServiceName(const std::string &service_instance){auto pos = service_instance.find_last_of('/');if (pos == std::string::npos)return service_instance;elsereturn service_instance.substr(0, pos);}private:std::mutex _mutex;std::unordered_set<std::string> _follow_services;std::unordered_map<std::string, ServiceChannel::ptr> _services;
};
相关文章:
brpc 安装及使用
介绍 brpc(Baidu Remote Procedure Call)是百度开源的一个高性能、通用的 RPC(远程过程调用)框架,其目标是让使用者能轻松构建高并发、分布式的应用程序。以下从多个方面详细介绍brpc: 核心特性 高性能 …...
ComfyUI学习笔记,案例四:inpaint
背景 ComfyUI学习笔记,案例四:inpaint,就是将一张图抠掉一块区域后还原,或者在一个图上重绘某个区域,感觉还是比较简单的。 它包含四个案例: inpaint_example,正向提示词 closeup photograph …...
【C++】智能指针RALL实现shared_ptr
个人主页 : zxctscl 专栏 【C】、 【C语言】、 【Linux】、 【数据结构】、 【算法】 如有转载请先通知 文章目录 1. 为什么需要智能指针?2. 内存泄漏2.1 什么是内存泄漏,内存泄漏的危害2.2 内存泄漏分类(了解)2.3 如何…...
利用迁移学习实现食物分类:基于PyTorch与ResNet18的实战案例
利用迁移学习实现食物分类:基于PyTorch与ResNet18的实战案例 在深度学习领域,训练一个高性能的模型往往需要大量的数据和计算资源。然而,通过迁移学习,我们能够巧妙地利用在大规模数据集上预训练好的模型,将其知识迁移…...
列日-巴斯通-列日:与VELO Senso TT+见证精彩时刻
近日,第111届列日-巴斯通-列日自行车赛落下帷幕,波加查毫无悬念地再度单飞夺冠。这场赛事不仅是速度与耐力的较量,更是装备与技术的完美结合。 在2025年第111届列日-巴斯通-列日自行车赛中,波加查以绝对优势再度单飞夺冠&a…...
C++笔记之委托
C++笔记之委托 code review! 文章目录 C++笔记之委托一、什么是委托?二、委托的常见应用场景2.1 事件委托(Event Delegation)2.2 C# 的委托类型(Delegate)2.3 对象组合中的委托(Design Delegation Pattern)三、C++ 委托模式示例四、委托的优点五、委托与23种设计模式的…...
Windows11 VS code 安装 Cline 调用 Github MCP 配置过程坑点汇总
背景 为了调研 MCP 在 windows 上如何使用本地的命令执行一些操作而实现自动化的过程,在 B 站视频的指导下,进行相应填坑过程,最终运行起来,并实现 github 自动化编程并提交代码的过程。 B 站 Cline 视频演示 Cline Cline 是一…...
SpringCloud多环境配置的一些问题
一、配置优先级(高到低) 命令行参数bootstrap.yaml/propertiesnacos配置config/applicaion.properties > config/applicaion.yml > config/applicaion.yamlapplicaion.properties > applicaion.yml > applicaion.yaml 有环境配置的会覆盖基础配置5的重复项&#…...
多语言笔记系列:Polyglot Notebooks 中运行 BenchmarkDotnet 基准测试
运行 BenchmarkDotnet 基准测试 在多语言笔记中,可以很方便的使用 BenchmarkDotnet 进行基准测试。 使用步骤 1. 安装 BenchmarkDotNet 包 // 默认包源 #i "nuget:https://api.nuget.org/v3/index.json"#r "nuget: BenchmarkDotNet, 0.13.12&quo…...
Model Context Protocol (MCP)笔记
目录 摘要MCP理论MCP的作用MCP 传输机制 Stdio 与 SSESTDIOSSE 传输部署模式 模型是如何确定工具的选用的?Fc x MCP x LangChain MCP快速开始编写客户端基于golang的mcp 摘要 Model Context Protocol(MCP,模型上下文协议)是由 An…...
【codeforces 2070c】二分答案详解
【codeforces 2070c】二分答案详解 二分答案转化成判定 对于任何问题,如果我们有了一个判定算法,那把解空间枚举并判定一遍,当然就可以得到解了。而当解空间具有单调性时,我们就可以使用二分法代替枚举。 考虑如下问题…...
启发式算法-禁忌搜索算法
禁忌搜索是一种可以用于解决组合优化问题的启发式算法,通过引入记忆机制跳出局部最优,避免重复搜索。该算法从一个初始解开始,通过邻域搜索策略来寻找当前解的邻域解,并在邻域解中选择一个最优解作为下一次迭代的当前解࿰…...
simulink 外循环与内循环执行流程
目录 前言 一、外循环 模型 执行流程 二、内循环 模型 执行流程 仓库 前言 某些需求需要使用到simulink外循环和内循环,本篇通过对其执行顺序进行记录,以便后续查阅。 一、外循环 模型 下面是我搭建的简单模型 执行流程 0-step:执行en step…...
Gradio全解20——Streaming:流式传输的多媒体应用(6)——构建视频流目标检测系统
Gradio全解20——Streaming:流式传输的多媒体应用(6)——构建视频流目标检测系统 本篇摘要20. Streaming:流式传输的多媒体应用20.6 RT-DETR模型构建视频流目标检测系统20.6.1 RT-DETR模型1. 模型介绍2. 使用示例 20.6.2 系统配置…...
比较两种判断相同二叉树的方法:递归与遍历序列对比
在二叉树操作中,判断两棵树是否相同是一个常见的问题。本文将对比两种不同的解决方案:递归法和遍历序列对比法,分析它们的优缺点,并探讨为何递归法是更优的选择。 问题描述 给定两棵二叉树的根节点 p 和 q,判断它们是…...
Java IO流核心处理方式详解
一、IO流概述 Java IO(Input/Output)流是处理输入输出操作的核心机制,通过流(Stream)的形式实现设备间的数据传输。所有操作都基于以下两个核心抽象: InputStream/OutputStream:字节流基类 Re…...
C++竞赛指南
关注支持,好运连连 目录 关注支持,好运连连 一、竞赛C核心优势 二、必备语法与STL组件 1. 输入输出优化 2. 常用STL容器 3. 算法函数 三、竞赛常用算法 1. 时间复杂度分析 2. 高频算法模板 二分查找 快速幂(模运算) …...
Python字符串全面指南:从基础到高级操作
字符串是Python编程中最基础也是最重要的数据类型之一。本文将全面介绍Python字符串的相关知识,从基础概念到高级操作,帮助您彻底掌握字符串的使用。 1. 字符串基础 1.1 字符串的概念 字符串是由一系列字符组成的不可变序列容器,存储的是字…...
【推荐】智慧矿山矿业信息化智能化资料汇总-共25份
智慧矿山矿业信息化智能化资料汇总 25 份: 有色金属矿山智能化采选生产线智能矿山建设与示范智能矿山建设实践与思考智慧矿山建设解决方案与实现途径以信息化、智能化为手段打造生态型、效益型国际一流示范矿山新型智能 X 荧光多通道高精度在线品位分析仪的研制与应…...
Oracle OCP认证考试考点详解083系列08
题记: 本系列主要讲解Oracle OCP认证考试考点(题目),适用于19C/21C,跟着学OCP考试必过。 36. 第36题: 题目 解析及答案: 关于数据库闪回(FLASHBACK DATABASE)功能,以下…...
备战蓝桥杯国赛第一天-atcoder-beginner-contest404
B. 因为只有四种情况,旋转90/180/270度后替换,直接替换,暴力即可 C. 循环图的定义是每个点出度为2,而且只有一个环的,所以先判断出度,再判断是否成环 #include <bits/stdc.h> using namespace st…...
Python异步编程进阶:深入探索asyncio高级特性
异步上下文管理器 (async with) 异步上下文管理器允许你在异步环境中管理资源,比如数据库连接或文件操作。 基本实现 class AsyncDatabaseConnection:async def __aenter__(self):print("建立数据库连接")await asyncio.sleep(0.5) # 模拟连接建立return selfas…...
【Java ee初阶】多线程(7)
一、线程池 线程池的一些参数: corePoolSize:核心线程数量 maximumPoolSize:核心线程数量临时线程数量 上述是“java 的线程池策略”(其他语言,其他库的线程池可能不同) keepAliveTime :临时线程的存活时间.临时线程…...
【PostgreSQL数据分析实战:从数据清洗到可视化全流程】6.2 预测分析基础(线性回归/逻辑回归实现)
👉 点击关注不迷路 👉 点击关注不迷路 👉 点击关注不迷路 文章大纲 PostgreSQL数据分析实战:预测分析基础(线性回归/逻辑回归实现)6.2 预测分析基础——线性回归与逻辑回归实现6.2.1 预测分析核心理论框架1…...
【NLP】29. 高效训练与替代模型:让语言模型更轻、更快、更强
高效训练与替代模型:让语言模型更轻、更快、更强 本文介绍语言模型如何通过结构优化与新模型探索,提升训练和推理的效率,适应资源受限环境,同时概述了一些 Transformer 替代模型的最新进展。 一、如何让语言模型更高效?…...
【LaTeX+VSCode本地Win11编译教程】
LaTeXVSCode本地编译教程参考视频: LaTeXVSCode本地编译教程 下面提供一种Win11的Latex环境配置和设置方案,首先vscode安装参考博客:【VscodeGit教程】,然后准备安装Latex相关组件 在 https://miktex.org/download 下载 miktex 并…...
组合两个表 --- MySQL [Leetcode 题目详解]
目录 题目链接 往期相关基础内容讲解博客 题目详解 1. 题目内容 2. 解题思路 3. 代码编写 题目链接 // 175. 组合两个表 往期相关基础内容讲解博客 // 聚合查询和联合查询博客 题目详解 1. 题目内容 // 编写解决方案,报告 Person 表中每个人的姓、名、城市…...
STM32 PulseSensor心跳传感器驱动代码
STM32CubeMX中准备工作: 1、设置AD 通道 2、设置一个定时器中断,间隔时间2ms,我这里采用的是定时器7 3、代码优化01 PulseSensor.c文件 #include "main.h" #include "PulseSensor/PulseSensor.h"/******************…...
macOS 上是否有类似 WinRAR 的压缩软件?
对于习惯使用 Windows 的用户来说,WinRAR 是经典的压缩/解压工具,但 macOS 系统原生并不支持 RAR 格式的解压,更无法直接使用 WinRAR。不过,macOS 平台上有许多功能相似甚至更强大的替代工具,以下是一些推荐࿱…...
Java求职面试:Spring Boot与微服务的幽默探讨
Java求职者面试:技术与幽默的碰撞 场景概述 在某互联网大厂的面试现场,面试官严肃认真,程序员则是一个搞笑的水货角色。面试者名叫张伟,年龄28岁,硕士学历,拥有5年的Java开发经验。以下是面试的详细过程。…...
《数字图像处理(面向新工科的电工电子信息基础课程系列教材)》封面颜色空间一图的选图历程
禹晶、肖创柏、廖庆敏《数字图像处理(面向新工科的电工电子信息基础课程系列教材)》 学图像处理的都知道,彩色图像的颜色空间很多,而且又是三维,不同的角度有不同的视觉效果,MATLAB的图又有有box和没有box。…...
Docker 使用下 (二)
Docker 使用下 (二) 文章目录 Docker 使用下 (二)前言一、初识Docker1.1 、Docker概述1.2 、Docker的历史1.3 、Docker解决了什么问题1.4 、Docker 的优点1.5 、Docker的架构图 二、镜像三、容器四、数据卷4.1、数据卷的概念4.2 、…...
【群晖NAS】Docker + WebStation + DDNS 部署无端口号HTTPs WordPress
前言 群晖提供官方的DDNS服务,可以直接配置一个类似于xxxx.synology.me的DDNS解析IPv4/IPv6到自己的NAS;群晖还有Web Station应用可以配置Docker的端口号映射,但是他自己占用了80端口,如果给自己的应用手动指定其他端口号&#x…...
手机SIM卡打电话时识别对方按下的DTMF按键(二)
手机SIM卡打电话时识别对方按下的DTMF按键(二) --本地AI电话机器人 前言 书接上篇,在上一篇章《手机打电话时如何识别对方按下的DTMF按键的字符》中,我们从理论的角度来论述了DTMF的频率组成。并尝试使用400Kb左右的【TarsosDS…...
N-Gram 模型
N-Gram 模型 什么是N-Gram?为什么叫 N-Gram?N-Gram怎么知道下一个词可能是什么?N-Gram 能做什么?N-Gram的问题 本文回答了四个问题: 一、N-Gram是什么?二、N-Gram为什么叫N-Gram?三、N-Gram具体…...
【漫话机器学习系列】240.真正类率(True Positive Rate,TPR)
理解真正类率(True Positive Rate,TPR):公式、意义与应用 在机器学习与深度学习模型评估中,"真正类率"(True Positive Rate,简称TPR)是一个非常重要的指标。TPR反映了分类…...
ThreadLocal源码深度剖析:内存管理与哈希机制
ThreadLocal是Java并发编程中的重要工具,它为每个线程提供独立的变量存储空间,实现了线程之间的数据隔离。本文将从源码实现角度,深入分析ThreadLocal的内部机制,特别是强弱引用关系、内存泄漏问题、ThreadLocalMap的扩容机制以及…...
Softmax回归与单层感知机对比
(1) 输出形式 Softmax回归 输出是一个概率分布,通过Softmax函数将线性得分转换为概率: 其中 KK 是类别数,模型同时计算所有类别的概率。 单层感知机 输出是二分类的硬决策(如0/1或1): 无概率解释&#x…...
数字社会学家唐兴通谈数字行动主义网络行动主义与标签行动主义,理解它才算抓住AI社会学与网络社会学关键所在
让我们继续探讨一个在数字时代至关重要的概念——数字行动主义(Digital Activism)、网络行动主义(Cyberactivism)以及标签行动主义(Hashtag Activism)。我将尽力从一个数字社会学家的角度,抽丝剥…...
PandasAI:对话式数据分析新时代
PandasAI:对话式数据分析新时代 引言项目概述分析基本信息 核心功能详解1. 自然语言查询处理2. 数据可视化生成3. 多数据源集成分析4. 安全沙箱执行5. 云平台协作功能 安装和使用教程1.环境要求2.安装步骤3.基本使用方法4.切换其他LLM 应用场景和实际价值1.适用业务…...
全球化电商平台AWS云架构设计
业务需求: 支撑全球三大区域(北美/欧洲/亚洲)用户访问,延迟<100ms处理每秒50,000订单的峰值流量混合云架构整合本地ERP系统全年可用性99.99%满足GDPR和PCI DSS合规要求 以下是一个体现AWS专家能力的全球化电商平台架构设计方…...
Linux 怎么使用局域网内电脑的网络访问外部
一次性 export http_proxy"http://192.168.0.188:7890" export https_proxy"http://192.168.0.188:7890"一直生效 写入 ~/.bashrc(或 ~/.bash_profile) nano ~/.bashrc加入这一行: export http_proxy"http://19…...
Python-numpy中ndarray对象创建,数据类型,基本属性
numpy库 numpy中的数据结构ndarrayndarray中的dtypendarray中的dtype的指定方式创建ndarray及指定dtype从列表创建ndarray使用 np.empty(), np.zeros(), np.ones() 和 np.full() 创建特定值的数组使用 np.arange() 创建等差数列数组使用 np.linspace() 创建等差数组使用np.logs…...
Python从入门到高手8.2节-元组的常用操作符
目录 8.2.1 元组的常用操作符 8.2.2 []操作符: 索引访问元组 8.2.3 [:]操作符:元组的切片 8.2.4 操作符:元组的加法 8.2.5 *操作符:元组的乘法 8.2.6 元组的关系运算 8.2.7 in操作符:查找元素 8.2.8 五一她玩了个狗吃…...
Python内置函数
Python作为一门简洁强大的编程语言,提供了丰富的内置函数(Built-in Functions),这些函数无需导入任何模块即可直接使用。本文将介绍Python中最常用、最重要的内置函数,帮助初学者快速掌握这些强大的工具。 官方地址&a…...
一款基于 .NET 开源的多功能的 B 站视频下载工具
前言 哔哩哔哩(B站)是一个知名的视频学习平台,作为程序员而言这是一个非常值得推荐的网站。今天大姚给大家推荐一款基于 .NET 开源的多功能的 B 站视频下载工具:downkyi。 项目介绍 downkyi(哔哩下载姬)…...
【PostgreSQL数据分析实战:从数据清洗到可视化全流程】5.2 数据分组与透视(CUBE/ROLLUP/GROUPING SETS)
👉 点击关注不迷路 👉 点击关注不迷路 👉 点击关注不迷路 文章大纲 5.2 数据分组与透视:CUBE/ROLLUP/GROUPING SETS深度解析5.2.1 数据准备与分析目标数据集与表结构分析目标 5.2.2 ROLLUP:层级化分组汇总功能与语法示…...
20、数据可视化:魔镜报表——React 19 图表集成
一、魔镜的预言本质 "数据可视化是霍格沃茨的预言水晶球,将混沌的数据星尘转化为可解读的命运轨迹!" 魔法部占卜司官员挥舞魔杖,Echarts与Three.js的图表矩阵在空中交织成动态星图。 ——基于《国际魔法联合会》第9号可视化协议&a…...
笔记本电脑升级计划(2017———2025)
ThinkPad T470 (2017) vs ThinkBook 16 (2025) 完整性能对比报告 一、核心硬件性能对比 1. CPU性能对比(i5-7200U vs Ultra9-285H) 参数i5-7200U (2017)Ultra9-285H (2025)提升百分比核心架构2核4线程 (Skylake)16核16线程 (6P8E2LPE)700%核心数制程工…...
Flutter——数据库Drift开发详细教程(四)
目录 参考正文表达式1.比较2.布尔代数3.算术BigIn 4.空值检查6.日期和时间7.IN和NOT IN8.聚合函数(例如 count 和 sum)8.1比较8.2算术8.4计数8.5group_concat8.9窗口函数 9.数学函数和正则表达式10.子查询10.1 标量子查询10.2 isInQuery10.3 存在10.4完整…...