Ainx框架基础路由模块

Go 语言数据库事务详解:从 db.Begin 到 Tx 的正确用法 本文详解Go语言中database/sql事务的正确用法,从*sql.Tx的底层模型出发,阐述事务与连接池的关系,提供标准事务模板,并强调使用db.BeginTx控制隔离级别与超时。重点剖析常见陷阱:误用db而非tx执行SQL、defer顺序错误、忽略Commit错误、事务过长导致资源耗尽等。结合可运行示例,涵盖事务内查询、预处理语句及保存点模拟嵌套事务,全面覆盖工程实践中的关键细节。 阅读详情
在这里插入图片描述

📕作者简介: 过去日记,致力于Java、GoLang,Rust等多种编程语言,热爱技术,喜欢游戏的博主。
📗本文收录于Ainx系列,大家有兴趣的可以看一看
📘相关专栏Rust初阶教程、go语言基础系列、spring教程等,大家有兴趣的可以看一看
📙Java并发编程系列,设计模式系列、go web开发框架 系列正在发展中,喜欢Java,GoLang,Rust,的朋友们可以关注一下哦!


📙 本文大部分都是借鉴刘丹冰大佬的zinx框架和文章,更推荐大家去读大佬的原文,本文只是个人学习的记录

Ainx框架基础路由模块

现在我们就给用户提供一个自定义的conn处理业务的接口吧,很显然,我们不能把业务处理的方法绑死在type HandFunc func(*net.TCPConn, []byte, int) error这种格式中,我们需要定一些interface{}来让用户填写任意格式的连接处理业务方法。

那么,很显然func是满足不了我们需求的,我们需要再做几个抽象的接口类。

IRequest 消息请求抽象类

我们现在需要把客户端请求的连接信息 和 请求的数据,放在一个叫Request的请求类里,这样的好处是我们可以从Request里得到全部客户端的请求信息,也为我们之后拓展框架有一定的作用,一旦客户端有额外的含义的数据信息,都可以放在这个Request里。可以理解为每次客户端的全部请求数据,Zinx都会把它们一起放到一个Request结构体里。

创建抽象IRequest层

在ainterface下创建新文件irequest.go。

ainx/ainterface/irequest.go

package ainterface

/*
IRequest 接口
实际是把客户端请求链接信息和请求数据包放在Request里
*/
type IRequest interface {
	GetConnection() IConnection //获取请求链接信息
	GetData() []byte            //获取请求消息的数据
	GetMsgID() uint32           //获取消息ID
}

不难看出,当前的抽象层只提供了两个Getter方法,所以有个成员应该是必须的,一个是客户端连接,一个是客户端传递进来的数据,当然随着Zinx框架的功能丰富,这里面还应该继续添加新的成员。

实现Request类

在anet下创建IRequest抽象接口的一个实例类文件request.go

ainx/anet/request.go

package anet

import "ainx/ainterface"

type Request struct {
	conn ainterface.IConnection //已经和客户端建立好的链接
	date []byte                 //客户端请求数据
}

// 获取请求链接信息
func (r *Request) GetConnection() ainterface.IConnection {
	return r.conn
}

// 获取请求消息的数据
func (r *Request) GetData() []byte {
	return r.msg.GetData()
}

// 获取请求的消息的ID
func (r *Request) GetMsgID() uint32 {
	return r.msg.GetMsgId()
}

IRouter 路由配置抽象类

现在我们来给Zinx实现一个非常简单基础的路由功能,目的当然就是为了快速的让Zinx步入到路由的阶段。后续我们会不断的完善路由功能。

创建抽象的IRouter层

在ainterface下创建irouter.go文件

ainx/ainterface/irouter.go

package ainterface

/*
	   路由接口,这里路由是 使用框架框架者给该链接自定的 处理业务方法
		路由里的IRequest 则包含用该链接的链接信息和该链接的请求数据信息
*/
type IRouter interface {
	PreHandle(request IRequest)  //在处理conn业务之前的钩子方法
	Handle(request IRequest)     //处理conn业务的方法
	PostHandle(request IRequest) //处理conn业务之后的钩子方法
}

我们知道router实际上的作用就是,服务端应用可以给Zinx框架配置当前链接的处理业务方法,之前的Zinx-V0.2我们的Zinx框架处理链接请求的方法是固定的,现在是可以自定义,并且有3种接口可以重写。

Handle:是处理当前链接的主业务函数

PreHandle:如果需要在主业务函数之前有前置业务,可以重写这个方法

PostHandle:如果需要在主业务函数之后又后置业务,可以重写这个方法

当然每个方法都有一个唯一的形参IRequest对象,也就是客户端请求过来的连接和请求数据,作为我们业务方法的输入数据。

实现Router类

在anet下创建router.go文件

package anet

import (
	"ainx/ainterface"
)

// 实现router时,先嵌入这个基类,然后根据需要对这个基类的方法进行重写
type BaseRouter struct{}

// 这里之所以BaseRouter的方法都为空,
// 是因为有的Router不希望有PreHandle或PostHandle
// 所以Router全部继承BaseRouter的好处是,不需要实现PreHandle和PostHandle也可以实例化
func (br *BaseRouter) PreHandle(req ainterface.IRequest)  {}
func (br *BaseRouter) Handle(req ainterface.IRequest)     {}
func (br *BaseRouter) PostHandle(req ainterface.IRequest) {}

我们当前的ainx目录结构应该如下:

├─ainterface
│      iconnection.go
│      irequest.go
│      irouter.go
│      iserver.go
│
└─anet
        connection.go
        request.go
        router.go
        server.go
        server_test.go

Ainx-V0.3-集成简单路由功能

IServer增添路由添加功能

我们需要给IServer类,增加一个抽象方法AddRouter,目的也是让Ainx框架使用者,可以自定一个Router处理业务方法。

ainx/ainterface/irouter.go

// 定义服务器接口
type IServer interface {
	//启动服务器方法
	Start()
	//停止服务器方法
	Stop()
	//开启业务服务方法
	Serve()
	//路由功能:给当前服务注册一个路由业务方法,供客户端链接处理使用
	AddRouter(router IRouter)
	// todo 路由分组 未来目标 添加类似hertz Group分组

}

Server类增添Router成员

有了抽象的方法,自然Server就要实现,并且还要添加一个Router成员.

ainx/anet/server.go

type Server struct {
	// 设置服务器名称
	Name string
	// 设置网络协议版本
	IPVersion string
	// 设置服务器绑定IP
	IP string
	// 设置端口号
	Port string
	//当前Server由用户绑定的回调router,也就是Server注册的链接对应的处理业务
	Router ainterface.IRouter
	//todo 未来目标提供更多option字段来控制server实例化
}

然后NewServer()方法, 初始化Server对象的方法也要加一个初始化成员


/*
创建一个服务器句柄
*/
func NewServer(name string) ainterface.IServer {
	s := &Server{
		Name:      name,
		IPVersion: "tcp4",
		IP:        "0.0.0.0",
		Port:      "8080",
		Router:    nil,
	}
	return s
}

Connection类绑定一个Router成员

ainx/anet/connection.go

type Connection struct {
	//当前链接的socket TCP套接字
	Conn *net.TCPConn
	// 当前链接的ID也可以称作SessionID,ID全局唯一
	ConnID uint32
	// 当前链接的关闭状态
	isClosed bool

	//该连接的处理方法router
	Router ainterface.IRouter

	// 告知该链接已经退出/停止的channel
	ExitBuffChan chan bool
}

在Connection调用注册的Router处理业务

ainx/anet/connection.go

// 处理conn读数据的Goroutine
func (c *Connection) StartReader() {
	fmt.Println("Reader Goroutine is  running")
	defer fmt.Println(c.RemoteAddr().String(), " conn reader exit!")
	defer c.Stop()

	for {
		//读取我们最大的数据到buf中
		buf := make([]byte, 512)
		_, err := c.Conn.Read(buf)
		if err != nil {
			fmt.Println("recv buf err ", err)
			c.ExitBuffChan <- true
			continue
		}
		//得到当前客户端请求的Request数据
		req := Request{
			conn: c,
			data: buf,
		}
		//从路由Routers 中找到注册绑定Conn的对应Handle
		go func(request ainterface.IRequest) {
			//执行注册的路由方法
			c.Router.PreHandle(request)
			c.Router.Handle(request)
			c.Router.PostHandle(request)
		}(&req)
	}
}

这里我们在conn读取完客户端数据之后,将数据和conn封装到一个Request中,作为Router的输入数据。

然后我们开启一个goroutine去调用给Zinx框架注册好的路由业务。

Ainx-V0.3代码实现

ainx/anet/server.go

package anet

import (
	"ainx/ainterface"
	"errors"
	"fmt"
	"net"
	"time"
)

type Server struct {
	// 设置服务器名称
	Name string
	// 设置网络协议版本
	IPVersion string
	// 设置服务器绑定IP
	IP string
	// 设置端口号
	Port string
	//当前Server由用户绑定的回调router,也就是Server注册的链接对应的处理业务
	Router ainterface.IRouter
	//todo 未来目标提供更多option字段来控制server实例化
}

// ============== 定义当前客户端链接的handle api ===========
func CallBackToClient(conn *net.TCPConn, data []byte, cnt int) error {
	//回显业务
	fmt.Println("[Conn Handle] CallBackToClient ...")
	if _, err := conn.Write(data[:cnt]); err != nil {
		fmt.Println("write back buf err", err)
		return errors.New("CallBackToClient error")
	}
	return nil
}

// ============== 实现 ainterface.IServer 里的全部接口方法 ========
// 开启网络服务
func (s *Server) Start() {
	fmt.Printf("[START] Server listenner at IP: %s, Port %s, is starting\n", s.IP, s.Port)

	// 开启一个go去做服务端的Listener业务
	// todo 未来目标是提供更多协议,可以利用if或者switch对IPVersion进行判断而选择采取哪种协议,下面整个方法要重写
	go func() {
		//1 获取一个TCP的Addr
		addr, err := net.ResolveTCPAddr(s.IPVersion, s.IP+":"+s.Port)
		if err != nil {
			fmt.Println("resolve tcp addr err: ", err)
			return
		}
		// 2 监听服务器地址
		listener, err := net.ListenTCP(s.IPVersion, addr)
		if err != nil {
			fmt.Println("listen", s.IPVersion, "err", err)
			return
		}
		//	  已经成功监听
		fmt.Println("start Ainx server  ", s.Name, " success, now listenning...")

		//TODO server.go 应该有一个自动生成ID的方法
		var cid uint32
		cid = 0
		//3 启动server网络连接业务
		for {
			//3.1 阻塞等待客户端建立连接请求
			conn, err := listener.AcceptTCP()
			if err != nil {
				fmt.Println("Accept err ", err)
				continue
			}
			//3.2 TODO Server.Start() 设置服务器最大连接控制,如果超过最大连接,那么则关闭此新的连接

			//3.3 处理该新连接请求的 业务 方法, 此时应该有 handler 和 conn是绑定的
			dealConn := NewConnection(conn, cid, s.Router)
			cid++

			//3.4 启动当前链接的处理业务
			go dealConn.Start()
		}
	}()
}
func (s *Server) Stop() {
	fmt.Println("[STOP] Zinx server , name ", s.Name)
	//TODO  Server.Stop() 将其他需要清理的连接信息或者其他信息 也要一并停止或者清理
}
func (s *Server) Serve() {
	s.Start()
	//TODO Server.Serve() 是否在启动服务的时候 还要处理其他的事情呢 可以在这里添加
	//阻塞,否则主Go退出, listenner的go将会退出
	for {
		time.Sleep(10 * time.Second)
	}
}
func (s *Server) AddRouter(router ainterface.IRouter) {
	s.Router = router
	fmt.Println("Add Router succ! ")
}

/*
创建一个服务器句柄
*/
func NewServer(name string) ainterface.IServer {
	s := &Server{
		Name:      name,
		IPVersion: "tcp4",
		IP:        "0.0.0.0",
		Port:      "8080",
		Router:    nil,
	}
	return s
}

ainx/anet/conneciont.go

package anet

import (
	"ainx/ainterface"
	"fmt"
	"net"
)

type Connection struct {
	//当前链接的socket TCP套接字
	Conn *net.TCPConn
	// 当前链接的ID也可以称作SessionID,ID全局唯一
	ConnID uint32
	// 当前链接的关闭状态
	isClosed bool

	//该连接的处理方法router
	Router ainterface.IRouter

	// 告知该链接已经退出/停止的channel
	ExitBuffChan chan bool
}

func (c *Connection) GetConnection() net.Conn {

	return c.Conn
}

// 创建链接的方法
func NewConnection(conn *net.TCPConn, connID uint32, router ainterface.IRouter) *Connection {
	c := &Connection{
		Conn:         conn,
		ConnID:       connID,
		isClosed:     false,
		Router:       router,
		ExitBuffChan: make(chan bool, 1),
	}
	return c
}

// 处理conn读数据的Goroutine
func (c *Connection) StartReader() {
	fmt.Println("Reader Goroutine is  running")
	defer fmt.Println(c.RemoteAddr().String(), " conn reader exit!")
	defer c.Stop()

	for {
		//读取我们最大的数据到buf中
		buf := make([]byte, 512)
		_, err := c.Conn.Read(buf)
		if err != nil {
			fmt.Println("recv buf err ", err)
			c.ExitBuffChan <- true
			continue
		}
		//得到当前客户端请求的Request数据
		req := Request{
			conn: c,
			data: buf,
		}
		//从路由Routers 中找到注册绑定Conn的对应Handle
		go func(request ainterface.IRequest) {
			//执行注册的路由方法
			c.Router.PreHandle(request)
			c.Router.Handle(request)
			c.Router.PostHandle(request)
		}(&req)
	}
}

// 启动连接,让当前链接工作
func (c *Connection) Start() {
	// 开启处理该链接读取到客户端数据之后的请求业务
	go c.StartReader()
	for {
		select {
		case <-c.ExitBuffChan:
			// 得到退出消息,不再阻塞
			return
		}
	}
}

// 停止链接,结束当前链接状态M
func (c *Connection) Stop() {
	//1.如果当前链接关闭
	if c.isClosed == true {
		return
	}
	c.isClosed = true
	//TODO Connection Stop() 如果用户注册了该链接的关闭回调业务,那么在此刻应该显示调用

	// 关闭socket链接
	err := c.Conn.Close()
	if err != nil {
		return
	}

	//通知从缓冲队列读数据的业务,该链接已经关闭
	c.ExitBuffChan <- true

	//关闭该链接全部管道
	close(c.ExitBuffChan)
}

// 从当前链接获取原始的socket TCPConn
func (c *Connection) GetTCPConnection() *net.TCPConn {
	return c.Conn
}

// 获取当前链接ID
func (c *Connection) GetConnID() uint32 {
	return c.ConnID
}

// 获取远程客户端地址信息
func (c *Connection) RemoteAddr() net.Addr {
	return c.Conn.RemoteAddr()
}

使用Ainx-V0.3完成应用程序

接下来我们在基于Ainx写服务器,就可以配置一个简单的路由功能了。

Server.go

package main

import (
	"fmt"
	"net"
	"time"
)

/*
模拟客户端
*/
func main() {

	fmt.Println("Client Test ... start")
	//3秒之后发起测试请求,给服务端开启服务的机会
	time.Sleep(3 * time.Second)

	conn, err := net.Dial("tcp", "127.0.0.1:8080")
	if err != nil {
		fmt.Println("client start err, exit!")
		return
	}

	for {
		_, err := conn.Write([]byte("Ainx V0.3"))
		if err != nil {
			fmt.Println("write error err ", err)
			return
		}

		buf := make([]byte, 512)
		cnt, err := conn.Read(buf)
		if err != nil {
			fmt.Println("read buf error ")
			return
		}

		fmt.Printf(" server call back : %s, cnt = %d\n", buf, cnt)

		time.Sleep(1 * time.Second)
	}
}

Client.go

package main

import (
	"ainx/ainterface"
	"ainx/anet"
	"fmt"
)

// ping test 自定义路由
type PingRouter struct {
	anet.BaseRouter //一定要先基础BaseRouter
}

// Test PreHandle
func (this *PingRouter) PreHandle(request ainterface.IRequest) {
	fmt.Println("Call Router PreHandle")
	_, err := request.GetConnection().GetConnection().Write([]byte("before ping ....\n"))
	if err != nil {
		fmt.Println("call back ping ping ping error")
	}
}

// Test Handle
func (this *PingRouter) Handle(request ainterface.IRequest) {
	fmt.Println("Call PingRouter Handle")
	_, err := request.GetConnection().GetConnection().Write([]byte("ping...ping...ping\n"))
	if err != nil {
		fmt.Println("call back ping ping ping error")
	}
}

// Test PostHandle
func (this *PingRouter) PostHandle(request ainterface.IRequest) {
	fmt.Println("Call Router PostHandle")
	_, err := request.GetConnection().GetConnection().Write([]byte("After ping .....\n"))
	if err != nil {
		fmt.Println("call back ping ping ping error")
	}
}

func main() {
	//创建一个server句柄
	s := anet.NewServer("[ainx V0.3]")

	s.AddRouter(&PingRouter{})

	//2 开启服务
	s.Serve()
}

从零开始学习 Go 1.25 编程 今天是你新生活的第一天,无论年龄、背景如何,改变从这一刻开始。CodeGym帮助成千上万普通人转型为程序员,从零基础到掌握Go语言,完成真实项目,甚至入职心仪岗位。Go语言简洁高效,适合服务器端开发,是云基础设施、微服务和高负载系统的首选。2026年正是入行良机,你的经验反而是优势。别犹豫,迈出第一步,你将收获技能、自信与全新人生。🚀 阅读详情

相关推荐

解决win11无法安装.net framework 3.5(包括.net2.0和3.0)错误代码:0x80070005

解决win11无法安装.net framework 3.5(包括.net2.0和3.0)错误代码:0x80070005

zeng699304的博客 2万+

Ainx框架实现 一

ainx是一个基于Golang编写的轻量级、高性能的TCP服务器框架,它特别适用于游戏服务器开发或者其他需要处理大量长连接场景的应用。

个人博客,记录了本人学习的各种有趣的技术。 2440

Python自然语言处理 NLTK 库用法入门教程【经典】

@本文来源于公众号:csdn2299,喜欢可以关注公众号 程序员学府 本文实例讲述了Python自然语言处理 NLTK 库用法。分享给大家供大家参考,具体如下: 在这篇文章中,我们将基于 Python 讨论自然语言处理(NLP)。本教程将会使用 Python NLTK 库。NLTK 是一个当下流行的,用于自然语言处理的 Python 库。 那么 NLP 到底是什么?学习 NLP 能带来什么好处? ...

python函数基础教程 1万+

Ainx的全局配置

📕作者简介:过去日记,致力于Java、GoLang,Rust等多种编程语言,热爱技术,喜欢游戏的博主。📗本文收录于系列,大家有兴趣的可以看一看📘相关专栏系列、spring教程等,大家有兴趣的可以看一看📙系列,系列、系列正在发展中,喜欢Java,GoLang,Rust,的朋友们可以关注一下哦!📙 本文大部分都是借鉴刘丹冰大佬的zinx框架和文章,更推荐大家去读大佬的,本文只是个人学习的记录。

个人博客,记录了本人学习的各种有趣的技术。 1251

组态王7.5和SQLsever数据库交互

摘要:本文详细介绍了组态王7.5与SQL Server 2016数据库交互的实现流程,包括建立连接、数据存储与查询操作。主要内容涵盖ODBC数据源配置、数据库表格创建、数据插入及查询功能实现(含日期控件查询)

gsjkwg的博客 1583

富芮坤FR801xH蓝牙协议栈启动流程和notify实现温度数据主动上传

文章目录一、蓝牙协议栈启动流程1.1 初始化代码1.2 初始化流程1.3 回调函数里的初始化二、notify实现2.1 notify介绍2.2 notify实现2.3.1 定义数据2.3.2 获取连接号conidx2.3.3 gatt_notification函数的使用三、notify温度上传测试3.1 蓝牙调试工具3.2 蓝牙调试器设置3.3 测试结果四、参考链接   基于sdk开发的好处是方便项目的快速落地,现在用的是SDK里面的源文件,目前只是学习FR801xH芯片的特性,裁剪这个SDK需要点时间,

weixin_43810563的博客 4322

AVR单片机-代码配置器(MCC)配置ADC

本文简要并实用的讲述了如何使用MPLAB中的MCC(代码配置器)配置AVR芯片ADC并S使用

SjiaM的博客 700

双足肌肉骨骼机器人

Clone Alpha的技术突破标志着人类进入生物-机械融合的新纪元,但其影响远超技术范畴。从伦理框架重建(如拉马克进化算法中的知识传递机制)到经济模式革新(如UBI应对机器人失业潮),需全球协作制定前瞻性政策。若放任技术无序扩张,人类社会或将面临“能力断层”与“控制权丧失”的双重危机;反之,若以人类福祉为核心导向,仿生机器人亦可成为弥合残障歧视、提升整体文明层级的钥匙。当下选择,将决定人类究竟是技术的创造者,还是被重构的客体。

百态·数智思维 | 聚焦大数据、量化与未来AI 988

Nutainx接口的调用

Nutainx自动化脚本的编写

weixin_45294285的博客 496

Far planner 代码系列(35)动态障碍物预处理_激光雷达部分

主要讲解动态障碍物在激光雷达部分的剔除机制

博客 1059

ArcGIS笔记13_利用ArcGIS制作岸线与水深地形数据?建立水动力模型之前的数据收集与处理?

在利用MIKE建立水动力模型之前,需要收集、处理和制作诸多数据和资料,主要有岸线数据、水深地形数据、开边界潮位驱动数据、风场数据、潮位和海流观测资料和站点潮汐调和常数资料等。本篇主要介绍这些资料的获取与处理。

晏长街的博客 5949

【STC单片机学习】第十六课:AD和DA转换

【朱老师课程总结 侵删】 第一部分、章节目录 1.16.1_2.AD转换及其相关背景知识1_2 1.16.3.原理图和数据手册 1.16.4.结合例程分析时序 1.16.5.代码实践 1.16.6.串口直接显示电压值 1.16.7.DA转换 第二部分、章节介绍 1.16.1.AD转换及其相关背景知识1 本节对整个课程做介绍,并且主要讲了模拟量和数字量这两个概念。1.16.2.AD转换及其相关背景知识2 本节接上节继续讲AD转换相关概念,主要是量程、精确度、分辨率、位...

搞IC的小冯 7252

卫星遥感影像处理:地物分类与变化检测

卫星遥感影像处理:地物分类与变化检测​ ,人工智能,计算机视觉,大模型,AI,卫星遥感技术通过搭载在卫星上的传感器获取地球表面的电磁波信息,为地物分类与变化检测提供了宏观、动态的观测数据。随着高分辨率遥感卫星(如高分系列、哨兵系列)的发展,遥感影像的空间分辨率、光谱分辨率和时间分辨率不断提升,为精准地物识别和动态变化监测奠定了基础。地物分类旨在将遥感影像中的像元按地表覆盖类型(如植被、水体、建筑、农田等)进行分类,而变化检测则通过对比不同时期的影像,识别地表覆盖的变化区域(如城市扩张、森林砍伐、土地退化等)

不踩坑,不知道坑有多深;不总结,踩过的坑白踩。 17万+

【FDE知识库】(1):AI 编程时代开发语言选型分析,云使用go,企业用java,算法python,底层c

AI 编程时代,开发语言选型需综合考量AI适配度、编译速度、跨平台与学习成本。Python以海量语料和即时执行成首选,适用于AI/ML与原型开发;TypeScript凭借类型系统与秒级构建,成为前端及应用层主流;Go以极速编译与统一风格,契合AI代理高效迭代需求。Rust/C++虽性能强,但编译慢、学习成本高,不适于快速试错。综合推荐:优先选Python、TypeScript、Go,兼顾效率与生态,实现最优AI协作体验。

freewebsys的专栏 626

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

每天10分钟学Go:第5课 switch分支判断

本课程讲解 Go 语言 switch 分支判断核心用法,涵盖单值匹配、多 case 合并、无表达式条件分支、fallthrough 穿透与类型 switch 断言,搭配可运行代码示例,带你掌握 Go 分支结构语法与实战写法。

2501_94567985的博客 259

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

TinyGo 驱动 ESP32 端侧 AI 推理实战:纯 Go 实现轻量机器学习模型部署全流程

基于乐鑫官方 TinyGo 教程,从零实现纯 Go 语言开发 ESP32 端侧 AI 推理应用,覆盖环境搭建、模型转换到全流程部署。

嵌入式扫地僧 517

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

每天10分钟学Go:第9课 Range循环

在 Go 里,`range` 常用来遍历切片、数组、字符串、映射和通道。它会在每次循环时,把当前元素的信息交给循环变量。前面《》我们已经会写普通的for循环,可以把range理解成一种更方便的遍历方式。

2501_94567985的博客 145

2026-11-11-Go分布式锁实战

线上偶发重复扣库存,查了半天是业务执行超过了锁的过期时间,锁提前释放,另一个请求拿到锁又执行了一遍。单机锁在多实例部署下失效,Redis SET NX PX 加锁、Lua 脚本原子释放、看门狗续期,这篇讲透分布式锁三大坑,附实现对照表和实战清单。

利威尔的博客,主要分享一些go后端,agent相关知识,都是最新最前沿而且是免费的,在我的专栏里有各种方向的详细分类和内容整理,详细内容请阅读主页置顶文章,希望对你有帮助。 296

每天10分钟学Go:第1课 环境搭建与第一个Go程序

本号专注分享实战干货、避坑指南、性能调优、面试重难点, 每一篇都是亲手落地测试,帮你少走弯路、快速提升核心竞争力。5、将go程序构建成可执行的二进制文件:go build hello-world.go。3、编辑go文件写入程序:vim hello-world.go。4、运行go程序:go run hello-world.go。2、创建go文件:touch hello-world.go。1、创建项目目录:mkdir go-test261111。2、配置go环境变量。

2501_94567985的博客 119

Go 泛型入门:类型参数、约束与 Map/Filter/Stack

掌握类型参数、约束、~ 与 union,写出通用 Map/Filter/Stack,并知道什么时候不该用泛型。

JudithHuang的博客 217

Go 测试实战:表驱动、Benchmark 与 httptest

从表驱动、子测试到 Benchmark/Fuzz/httptest,建立“测行为不测实现”的测试习惯。

JudithHuang的博客 200

day01-认识Go语言 + golang环境的安装

Go语言由Google开发,2009年发布,兼具编译型性能与脚本语言易用性。其优势包括运行快、语法简洁、跨平台构建、丰富标准库及原生并发支持(goroutine与channel),适用于微服务、区块链等场景。安装时需配置GOROOT(安装路径)、GOPATH(工作空间,含pkg和bin目录)及GOBIN,并将%GOROOT%\bin、%GOBIN%、%GOPATH%加入系统Path。通过命令行验证环境后,可使用GoLand等IDE进行开发,快速上手高效编程。

2301_77190282的博客 230

Go CPU 剖析的“地基“:信号、CAS、写屏障、无锁环形缓冲

本文通过“卡点自查表”梳理Go CPU剖析(cpuprof.go)中反直觉设计的底层逻辑,聚焦信号处理、CAS自旋锁、写屏障与无锁缓冲四大核心机制。指出所有设计皆源于信号处理器“不可阻塞、不碰堆、不持锁”的铁律,进而推导出:CompareAndSwap一次即走、环形缓冲无锁写入、预分配内存等策略的本质是向“在任意指令间被中断”这一事实妥协。结合多核并发与操作系统调度原理,揭示了高性能采样器如何在极端约束下实现低延迟、高吞吐。

不愿言弃-念何的博客 636

Go1.25 升级后 GoLand 调试提示【变量不可用】解决方案

顶部菜单Help→在弹出的配置文件中添加下面一行,路径替换为你本机 dlv.exe 真实路径Windows 路径使用正斜杠,不要用反斜杠保存配置文件,完全重启 GoLand(不是只重启调试会话)Go 大版本升级后,优先检查 Delve 兼容性,这是 Go1.24+、Go1.25 最常见的调试踩坑点。升级dlv + 指定dlv路径 + 关闭编译优化参数,90% 的“变量不可用”问题都可以解决。

关于代码的那些事 235

Go FX 依赖注入框架:从入门到实战

FX 的核心思想就是“声明式依赖管理”—— 你只需要告诉它"我有这些组件,它们需要什么",剩下的创建、排序、生命周期都由框架自动处理。特性传统方式FX 方式依赖顺序手动维护自动解析生命周期手写 start/stopfx.Hook 自动调度测试难度高(需真实依赖)低(接口易 mock)代码可读性分散在各处集中在 module 中错误提示运行时 panic启动时清晰报错对于中大型 Go 项目,FX 能显著降低代码耦合度,提升可测试性和可维护性。

ggaofengg的专栏 173

Go 定时任务实战:工业边缘场景下的 robfig/cron

工业边缘网关里有大量周期性工作:设备状态轮询、数据同步、定时上报、日志清理。,本文从角度梳理其用法、任务封装、并发控制与常见的坑。

ZenovaEdgeOS的博客 456
上一篇: Java框架篇面试题
下一篇: kitex 入门和基于grpc的使用
过去日记
过去日记 新星创作者: 后端开发技术领域 新星创作者: 后端开发技术领域
博客等级 码龄3年 5343粉丝 225原创
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

过去日记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值