Go 语言gin框架的web
节省时间与精力,更高效地打造稳定可靠的Web项目:基于Go语言和Gin框架的完善Web项目骨架。无需从零开始,直接利用这个骨架,快速搭建一个功能齐全、性能优异的Web应用。充分发挥Go语言和Gin框架的优势,轻松处理高并发、大流量的请求。构建可扩展性强、易于维护的代码架构,保证项目的长期稳定运行。同时,通过集成常用功能模块和最佳实践,减少繁琐的开发工作,使您专注于业务逻辑的实现。
该骨架每个组件之间可单独使用,组件之间松耦合,高内聚,组件的实现基于其他三方依赖包的封装。
目前该骨架实现了大多数的组件,比如事件
,中间件
,日志
,配置
,参数验证
,命令行
,定时任务
等功能,目前可以满足大多数开发需求,后续会持续维护更新功能。青丝南开:https://www.cnblogs.com/smallKilts/p/17726021.html
github地址:https://github.com/czx-lab/skeleton
gitee地址:https://gitee.com/neddie/skeleton
设置环境变量并下载项目依赖
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct
go mod download
运行项目
go run ./cmd/main.go
项目编译打包运行
go build ./cmd/main.go// 编译
make build// 运行
make run// 编译与运行
make// 运行项目
./main
项目目录结构说明
├─app
│ ├─command ---> 命令行
│ ├─controller
│ │ └─base.go ---> BaseController,主要定义了request参数验证器validator
│ ├─event
│ │ ├─entity ---> 事件实体目录
│ │ ├─listen ---> 事件监听执行脚本目录
│ │ └─event.go ---> 事件注册代码
│ │
│ ├─middleware ---> 中间件代码目录
│ ├─request ---> 请求参数校验代码目录
│ │ └─request.go ---> 参数验证器
│ └─task ---> 定时任务代码目录
│ └─task.go ---> 注册定时任务脚本
├─cmd ---> 项目入口目录
│ └─cli ---> 项目命令行模式入口目录
├─config
│ └─config.yaml ---> 配置文件
├─internal ---> 包含第三方包的封装
├─router ---> 路由目录
│ └─router.go
├─storage ---> 日志、资源存储目录
│ └─logs
└─test ---> 单元测试目录
骨架全局变量
该骨架中全局变量如下,可直接查看internal/variable.go
文件。
var (// 项目更目录BasePath string// Log日志Log *zap.Logger// 配置,Viper封装Config *config.Config// 数据库GormDB *gorm.DBMongoDB *mongo.MongoDBRedis *redis.ClientCrontab *crontab.Crontab// RabbitMQAmqp mq.RabbitMQInterface// rocketmq, 目前官方RocketMQ Golang SDK一些功能尚未完善,暂时不可用MQ mq.Interface// 事件Event *event.Event
)
基础功能
路由
该骨架的web框架是gin,所以路由定义可直接阅读Gin框架的文档。
在该骨架中定义注册路由需要在router
文件夹下面的router.go
文件中的func (*AppRouter) Add(server *gin.Engine)
方法定义注册:
server.GET("/foo", func(ctx *gin.Context) {ctx.String(http.StatusOK, "hello word!")
})
也可以通过自己定义路由的定义注册,只需要实现github.com/czx-lab/skeleton/internal/server/router
下面的Interface
接口。如下示例:
在router目录下定义了一个CustomRouter
结构体,该结构体实现了Interface
接口
package routerimport ("net/http""skeleton/internal/server""github.com/gin-gonic/gin"
)type CustomRouter struct {server server.HttpServer
}func NewCustom(srv server.HttpServer) *CustomRouter {return &CustomRouter{srv,}
}func (*CustomRouter) Add(srv *gin.Engine) {srv.GET("/custom", func(ctx *gin.Context) {ctx.String(http.StatusOK, "custom router")})
}
需要注意的是,如果是自定义路由注册,需要修改项目
cmd
文件夹下面的main.go
入口文件,通过http.SetRouters(router.NewCustom(http))
注册给gin
中间件
定义中间件与gin
框架一样,该估计默认实现了panic异常的中间件,可以查看internal/server/middleware
文件夹中的exception.go
文件。
如果需要定义其他的中间件并加载注册,可以将定义好的中间件通过server.HttpServer
接口的SetMiddleware(middlewares ...middleware.Interface)
方法注册加载,
比如我们实现如下自定义全局中间件middleware/custom.go
:
type Custom struct{}func (c *Custom) Handle() gin.HandlerFunc {return func(ctx *gin.Context) {fmt.Println("Custom middleware exec...")}
}
然后在定义路由的地方使用server.SetMiddleware(&middleware.Custom{})
注册中间件。
定义全局路由中间件可以参考router/router.go
中的New
方法。
如果是局部中间件,可以直接在具体的路由上注册,参考gin路由中间件的用法
日志
在该骨架中的日志是直接对go.uber.org/zap
的封装,使用时,直接通过全局变量variable.Log
访问写入日志,可直接使用zap支持的所有方法。
package demo
import "skeleton/internal/variable"
func Demo() {variable.Log.Info("info message")
}
日志文件默认是以json
格式写入到storage/logs/system.log
里面
配置
配置项的定义直接在config/config.yaml
文件中定义,并且配置的读取写入是通过封装github.com/spf13/viper
实现,在该骨架中,只提供了如下一些获取配置的方法:
type ConfigInterface interface {Get(key string) anyGetString(key string) stringGetBool(key string) boolGetInt(key string) intGetInt32(key string) int32GetInt64(key string) int64GetFloat64(key string) float64GetDuration(key string) time.DurationGetStringSlice(key string) []string
}
需要注意的是,骨架中对配置项的获取做了缓存的处理,第一次加载是在文件中获取,后面每次回去都是在cache
中获取,目前cache
默认只支持memory
,骨架中也支持自定义cache
的方法,只需要实现config.CacheInterface
接口就可以,比如需要使用redis
作为配置缓存,可以通过下面的方式处理:
type ConfigRedisCache struct {}var _ config.CacheInterface = (*ConfigRedisCache)(nil)func (c *ConfigRedisCache) Get(key string) any {return nil
}func (c *ConfigRedisCache) Set(key string, value any) bool {return true
}func (c *ConfigRedisCache) Has(key string) bool {return true
}func (c *ConfigRedisCache) FuzzyDelete(key string) {}
然后将ConfigRedisCache
结构体配置到config.Options
中,如下所示,修改internal/bootstrap/init.go
初始化配置的方法:
variable.Config, err := config.New(driver.New(), config.Options{BasePath: './',Cache: &ConfigRedisCache{}
})
config.yaml
基础配置如下:
# http配置
HttpServer:Port: ":8888"# 服务模式,和gin的gin.SetMode的值是一样的Mode: "debug"
# socket配置
Websocket:WriteReadBufferSize: 2048HeartbeatFailMaxTimes: 4PingPeriod: 20ReadDeadline: 100WriteDeadline: 35PingMsg: "ping"# 数据库配置
Database:# 可以查看GORM相关的配置选项Mysql:SlowThreshold: 5LogLevel: 4ConnMaxLifetime: 1MaxIdleConn: 2MaxOpenConn: 2ConnMaxIdleTime: 12Reade:- "root:root@tcp(192.168.1.4:3306)/test?charset=utf8mb4&loc=Local&parseTime=True"Write: "root:root@tcp(192.168.1.4:3306)/test?charset=utf8mb4&loc=Local&parseTime=True"# mongo数据库的基础配置Mongo:Enable: falseUri:MinPoolSize: 10MaxPoolSize: 20Redis:Disabled: falseAddr: "192.168.1.4:6379"Pwd: ""Db: 0PoolSize: 20MaxIdleConn: 30MinIdleConn: 10# 单位(秒)MaxLifeTime: 60# 单位(分)MaxIdleTime: 30# 定时任务
Crontab:Enable: true# 消息队列,使用rocketmq
MQ:Enable: trueServers:- "127.0.0.1:9876"Retries: 1ProducerGroupName: "ProducerGroup"ConsumerGroupName: "ConsumerGroup"# RabbitMQ
Amqp:Enable: trueAddr: "amqp://guest:guest@127.0.0.1:5672/"
事件机制
-
定义事件实体
在
app/event/entity
目录下定义一个事件实体,该实体实现了event.EventInterface
接口:package entitytype DemoEvent struct {}func (d *DemoEvent) EventName() string {return "demo-event" }func (d *DemoEvent) GetData() any {return "demo param" }
-
定义事件监听
在
app/event/listen
目录中定义一个DemoEventListen
事件监听,并且该DemoEventListen
结构体必须要实现event.Interface
接口:package listenimport ("fmt"event2 "skeleton/app/event/entity""skeleton/internal/event" )type DemoEventListen struct { }func (*DemoEventListen) Listen() event.EventInterface {return &event2.DemoEvent{} }func (*DemoEventListen) Process(data any) (any, error) {return fmt.Sprintf("%v --> %s", data, "exec DemoEventListen.Process"), nil }
-
最后需要将事件进行注册,在
app/event/event.go
文件中的Init
方法内执行:variable.Event.Register(&listen.DemoEventListen{})
-
调用事件执行
variable.Event.Dispatch(&entity.DemoEvent{})
验证器
gin框架本身内置了validator
校验,骨架里面只是对其参数的校验做了统一的校验入口。
通过如下方式获取进行参数的校验,并设置中文错误提示:
type Param struct {Name int `binding:"required" form:"name" query:"name" json:"name"`
}
appRequest, err := AppRequest.New("zh")
if err != nil {return
}
var data Param
errMap := appRequest.Validator(ctx, &data)
fmt.Println(errMap)
骨架里面已经实现了默认的参数校验,可以在app/request/request.go
文件中查看。并且在controller
目录中base.go
有一个Validate(ctx *gin.Context, param any)
方法,在其他controller中要进行参数校验的时候,只需要继承base
结构体,然后调用Validate
方法。
package controllerimport "github.com/gin-gonic/gin"type DemoController struct {base
}type DemoRequest struct {Id int `binding:"required" form:"id" query:"id" json:"id"`
}func (d *DemoController) Index(ctx *gin.Context) {var param DemoRequestif err := d.base.Validate(ctx, ¶m); err == nil {ctx.JSON(http.StatusOK, gin.H{"data": param})} else {ctx.JSON(http.StatusBadRequest, gin.H{"message": err})}
}
验证规格参考
github.com/go-playground/validator
官方文档
命令行
基于github.com/spf13/cobra
封装
-
定义命令
在
app/command
目录中定义自己的命令,比如自定义一个输出success ok
的命令package commandimport ("fmt""github.com/spf13/cobra" )type FooCommand struct {}func (f *FooCommand) Command() *cobra.Command {return &cobra.Command{Use: "foo",Short: "命令使用简介.",Long: `命令介绍.`,Run: func(cmd *cobra.Command, args []string) {str, _ := cmd.Flags().GetString("name")fmt.Printf("success, %s", str)},} }func (f *FooCommand) Flags(root *cobra.Command) {root.PersistentFlags().String("name", "", "命令参数") }
-
注册命令
需要在
cmd/cli/cli.go
中的main
方法内注册自定义命令。 -
执行命令
go run cmd/cli/cli.go foo --name ok
-
查看命令信息
go run cmd/cli/cli.go help// 或者 go run cmd/cli/cli.go foo --help
定时任务
定时是通过封装github.com/robfig/cron/v3
实现
-
定义定时任务方法
在
app/task
目录下定义执行方法,比如每一分钟打印success
字符package taskimport "fmt"type SuccessTask struct { }// 时间规则 func (s *SuccessTask) Rule() string {return "* * * * *" }func (s *SuccessTask) Execute() func() {return func() {fmt.Println("success")} }
-
加载定时任务
需要在
app/task/task.go
文件中的Tasks
方法内,加载自定义的任务,参考task目录下的task.go
文件
Websocket
-
消息处理与链接关闭监听
该骨架中的
websocket
是对github.com/gorilla/websocket
依赖库的封装,在编写通信功能时,只需要实现websocket.MessageHandler
接口:import (AppSocket "skeleton/internal/server/websocket" )type socketHandler struct {}// 消息处理 func (s *socketHandler) OnMessage(message AppSocket.Message) {fmt.Println(fmt.Sprintf("mt: %v,data: %s, uuids: %v", message.MessageType, message.Data, message.Subkeys)) }func (s *socketHandler) OnError(key string, err error) {fmt.Printf("socket err: %s, client: %s", err, key) }func (s *socketHandler) OnClose(key string) {fmt.Printf("socket closed. client:%s", key) }
-
创建链接Websocket
import ("github.com/google/uuid""github.com/gin-gonic/gin"AppSocket "skeleton/internal/server/websocket" )var client AppSocket.SocketClientInterfacefunc init() {client, _ = AppSocket.NewSocket(AppSocket.WithHandler(&socketHandler{})) }func Connect(ctx *gin.Context) {subkey := uuid.New().String()client.Connect(ctx, subkey) }
-
发送消息
这里可以发送全部信息给全部用户,或者发送给用户,
AppSocket.Message
结构体中Subkeys []string
表示需要发送给哪些用户:client.WriteMessage(AppSocket.Message{MessageType: websocket.TextMessage,Data: []byte("服务端收到消息并回复ok"),Subkeys: []string{"9bae9c4f-87a8-46b1-b1b9-4f37b63a7d19"}})
如果
Subkeys
是空切片数组,会将消息推送给全部在线用户 -
心跳消息
websocket标准协议实现隐式心跳,Server端向Client端发送ping格式数据包,浏览器收到ping标准格式,自动将消息原路返回给服务器
-
其他方法
GetAllKeys() []string
:获取所有websocket连接uuidGetClientState(key string) bool
:获取指定客户端在线状态
消息中间件
RabbitMQ
RabbitMQ消息中间件的使用可参考test/rmq_test.go
单元测试,同时骨架中也实现了RabbitMQ的简单模式示例:app/amqp
目录下可查看
全局变量variable.Amqp
返回mq.RabbitMQInterface
接口,接口中的方法可查看源文件查看
-
定义消费者
consumer
定义
consumer
,需要实现mq.ConsumerHandler
接口,该接口可查看internal/mq/rabbitmq.go
文件中的定义,比如定义一个简单模式的消费者:import ("fmt""skeleton/internal/mq""github.com/streadway/amqp" )type FooConsumer struct{}func (*FooConsumer) Option() mq.ConsumerOption {return mq.ConsumerOption{CommonOption: mq.CommonOption{Mode: mq.SimpleMode,QueueName: "foo",Durable: false,AutoDelete: false,Exclusive: false,NoWait: false,Args: nil,},AutoAck: true,NoLocal: false,} }func (*FooConsumer) Exec(msg <-chan amqp.Delivery) {for v := range msg {fmt.Printf("consumer message:%v\n", string(v.Body))} }
当我们定义好消费者后,需要通过
mq.InitConsumer
中的InitConsumers() []ConsumerHandler
进行注册,骨架中注册文件已写死,项目启动时,会执行InitConsumers
方法,查看app/amqp/amqp.go
文件的代码:package amqpimport ("skeleton/app/amqp/consumer""skeleton/internal/mq" )type Amqp struct{}func (*Amqp) InitConsumers() []mq.ConsumerHandler {return []mq.ConsumerHandler{&consumer.FooConsumer{},} }
-
发送消息
producer
通过全局变量
variable.Amqp
的方法发送消息:opts := mq.ProducerOption{CommonOption: mq.CommonOption{Mode: mq.SimpleMode,QueueName: "foo",Durable: false,AutoDelete: false,Exclusive: false,NoWait: false,Args: nil,},Message: amqp.Publishing{ContentType: "text/plain",Body: []byte("test message"),},Mandatory: false,Immediate: false,}variable.Amqp.Publish(opts)
RocketMQ
注意:目前官方RocketMQ Golang SDK一些功能尚未完善,暂时不可用
消息中间件的使用可参考test/mq_test.go
单元测试
骨架对外提供了mq.Interface
接口中的方法,可查看internal/mq/rocketmq.go
文件下的Interface
接口定义
定义consumer时,只需要实现mq.ConsumerInterface
接口即可,详见mq_test
单元测试
相关文章:

Go 语言gin框架的web
节省时间与精力,更高效地打造稳定可靠的Web项目:基于Go语言和Gin框架的完善Web项目骨架。无需从零开始,直接利用这个骨架,快速搭建一个功能齐全、性能优异的Web应用。充分发挥Go语言和Gin框架的优势,轻松处理高并发、大…...
Docker底层原理:Cgroup V2的使用
文章目录 检查 cgroup2 文件系统是否已加载检查系统是否已挂载 cgroup2 文件系统创建 cgroup2 层次结构查看 cgroup2 开启的资源控制类型启用 cgroup2 资源控制设置 cgroup2 资源限制加入进程到 cgroup2 检查 cgroup2 文件系统是否已加载 cat /proc/filesystems | grep cgroup…...

历年上午真题笔记(2014年)
解析:A 网络设计的三层模型 : 接入层:Layer 2 Switching,最终用户被许可接入网络的点,用户通过接入层可以访问网络设备。 汇聚层:Layer2/3 Switching,访问层设备的汇聚点,负责汇接配线单元,利用二、三层技术实现工作组分段及网络故障的隔离,以免对核心层网络设备造…...

数据库软考知识
分布式数据库透明性 封锁 加上共享锁之后只能加共享锁,加上排他锁之后,啥锁都不能加。 分布式数据库特性 伪传递定理 SQL函数定义,有点冷 来了奥,更冷 存储过程 很重要,下午第二大题也是数据库...

学习笔记|配对样本均数T检验|SPSS常用的快捷键|规范表达|《小白爱上SPSS》课程:SPSS第六讲 | 配对样本均数T检验
目录 学习目的软件版本原始文档配对样本均数T检验一、实战案例二、案例解析三、统计策略四、SPSS操作1、正态性检验2、配对样本T检验 五、结果解读六、规范报告1、规范表格2、规范文字 划重点Tips:SPSS常用的快捷键 学习目的 SPSS第六讲 | 配对样本均数T检验 软件版本 IBM S…...
python内置模块smtplib、email 发送电子邮件
一、简介 smtplib 是 Python 的标准库之一,用于发送电子邮件。它提供了一个简单的接口来连接到 SMTP(Simple Mail Transfer Protocol)服务器,并通过该服务器发送电子邮件。 email 是 Python 的标准库之一,用于处理电子…...
Qt使用QWebEngineView一些记录
1.关闭软件警告: Release of profile requested but WebEnginePage still not deleted. Expect troubles! 原因,系统退出关闭view,没有释放page。 解决办法:手动释放page 顺便把view也释放了。 Widget::~Widget() {updateIni…...
【2023.10.30练习】C语言-判断等式成立
计算机能力挑战初赛2020.20题 题目描述: 输入正整数A、B、C(0<A,B,C<10000),若用、-、*、/、%之一组成等式(即ABC,是上述运算符之一,),则输出“YES”,否则输出“NO”; 输入: 第一行输入…...

Wpf 使用 Prism 实战开发Day03
一.实现左侧菜单绑定 效果图: 1.首先需要在项目中创建 mvvm 的架构模式 创建 Models ,放置实体类。 实体类需要继承自Prism 框架的 BindableBase,目的是让实体类支持数据的动态变更! 例如: 系统导航菜单实体类 / <summary>/// 系统导航菜单实体类…...

JavaEE-cookie和session
本部分内容包括 cookie基本概念,sendcookies和getcookies代码; session基本概念,session实现登陆界面; 上述过程中涉及的代码如下: 1 import javax.servlet.ServletException; import javax.servlet.annotation.WebSe…...

Java设计模式之命令模式
目录 定义 结构 案例 优点 缺点 使用场景 JDK源码解析 Thread中start与run方法的区别 定义 将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通,这样方便将命令对象进行存储、传递、调用、增…...

记录一段帮朋友写的代码,使用牛顿-拉夫逊方法解方程
要求 已知公式: t G A B F r B r 2 2 F A 2 B G A F ln ( r − A ) C o n s t t\frac{GAB}{F}r\frac{Br^2}{2F}\frac{A^2BGA}{F}\ln (r-A)Const tFGABr2FBr2FA2BGAln(r−A)Const 其中 t 的值为0-1000,每间隔25取一次值A2.12941E-10B0.…...

滑动窗口限流算法实现一
固定算法 原理:固定算法是将时间线分隔成固定大小的时间窗口,每个窗口都会有个计数器,用来记录窗口时间范围内的请求总数,如果窗口的请求总数达到最大限定值,会认定流量超限。比如将窗口大小设为1分钟,每分…...

简单明了!网关Gateway路由配置filters实现路径重写及对应正则表达式的解析
问题背景: 前端需要发送一个这样的请求,但出现404 首先解析请求的变化: http://www.51xuecheng.cn/api/checkcode/pic 1.请求先打在nginx,www.51xuecheng.cn/api/checkcode/pic部分匹配到了之后会转发给网关进行处理变成localho…...

EMQX内置Web管理控制台-Dashboard
一、Dashboard概述 EMQX Dashboard官网文档:https://docs.emqx.com/zh/enterprise/v5.1/dashboard/introduction.html 1、简介 EMQX 为用户提供了一个功能强大的内置管理控制台,即 EMQX Dashboard。通过这个控制台的 Web 界面,用户可以轻松监…...

计算机网络重点概念整理-第四章 网络层【期末复习|考研复习】
计算机网络复习系列文章传送门: 第一章 计算机网络概述 第二章 物理层 第三章 数据链路层 第四章 网络层 第五章 传输层 第六章 应用层 第七章 网络安全 计算机网络整理-简称&缩写 文章目录 前言四、网络层4.1 网络层功能4.1.1 电路交换、报文交换与分组交换4.1…...
数组转树形数据
const nodes [{ id: 3, name: 节点C, pid: 1 },{ id: 6, name: 节点F, pid: 3 },{ id: 0, name: root, pid: null },{ id: 1, name: 节点A, pid: 0 },{ id: 8, name: 节点H, pid: 4 },{ id: 4, name: 节点D, pid: 1 },{ id: 2, name: 节点B, pid: 0 },{ id: 5, name: 节点E, p…...
react动态插入样式
在开发组件过程中,偶尔需要动态的插入css,比如在在iframe中渲染组件后,iframe中是没有样式的,所以需要手动插入样式。 插入样式 通常是在useLayoutEffect中动态创建style标签 useLayoutEffect(() > {if (!ref.current) {cons…...

OkHttp网络框架深入理解-SSL握手与加密
OkHttp简介 由Square公司贡献的一个处理网络请求的开源项目,是目前Android使用最广泛的网络框架。从Android4.4开始HttpURLConnection的底层实现采用的是OkHttp。 特点: 支持HTTP/2并允许对同一主机的所有请求共享一个套接字通过连接池,减少了请求延迟…...

Mac 安装使用NPM及常用命令
环境: Mac 工具: NPM 可通过官网查询一些模块相关 NPM Doc 通过官网文档了解更多的关于NPM的使用 安装 NPM是Node.js的包管理工具,可用于解决 Node.js在代码部署上的问题。 新版本的Node.js已经集成了NPM, 因此可通过下载 Nod…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...

docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...

高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...
Unit 1 深度强化学习简介
Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...
站群服务器的应用场景都有哪些?
站群服务器主要是为了多个网站的托管和管理所设计的,可以通过集中管理和高效资源的分配,来支持多个独立的网站同时运行,让每一个网站都可以分配到独立的IP地址,避免出现IP关联的风险,用户还可以通过控制面板进行管理功…...

论文阅读:Matting by Generation
今天介绍一篇关于 matting 抠图的文章,抠图也算是计算机视觉里面非常经典的一个任务了。从早期的经典算法到如今的深度学习算法,已经有很多的工作和这个任务相关。这两年 diffusion 模型很火,大家又开始用 diffusion 模型做各种 CV 任务了&am…...

【Linux】Linux安装并配置RabbitMQ
目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...

Qt的学习(一)
1.什么是Qt Qt特指用来进行桌面应用开发(电脑上写的程序)涉及到的一套技术Qt无法开发网页前端,也不能开发移动应用。 客户端开发的重要任务:编写和用户交互的界面。一般来说和用户交互的界面,有两种典型风格&…...

leetcode73-矩阵置零
leetcode 73 思路 记录 0 元素的位置:遍历整个矩阵,找出所有值为 0 的元素,并将它们的坐标记录在数组zeroPosition中置零操作:遍历记录的所有 0 元素位置,将每个位置对应的行和列的所有元素置为 0 具体步骤 初始化…...