feat(config): 添加超时空地图配置和时间地图查询功能 新增IsTimeSpace字段用于标识地图是否为超时空地图, 添加TimeMap API接口支持查询超时空地图配置 perf(socket): 优化XORDecryptU解密函数减少内存分配 基于bytebufferpool实现缓冲区池化,大幅降低高频调用下的 内存分配和GC压力,提升性能表现 refactor(utils): 优化packVal序列化函数提升性能和稳定性 减少反射开销,
This commit is contained in:
@@ -19,6 +19,7 @@ import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/panjf2000/gnet/v2"
|
||||
"github.com/valyala/bytebufferpool"
|
||||
)
|
||||
|
||||
func (s *Server) Boot(serverid, port uint16) error {
|
||||
@@ -305,21 +306,41 @@ func (s *Server) onevent(c gnet.Conn, v []byte) {
|
||||
}
|
||||
|
||||
// XORDecryptU 优化后的异或解密:减少内存分配,支持复用缓冲区
|
||||
// XORDecryptU 基于bytebufferpool优化的异或解密函数
|
||||
// 保留原有接口,无侵入式优化,高频调用下大幅减少内存分配和GC
|
||||
func XORDecryptU(encryptedData []byte, key uint32) []byte {
|
||||
if len(encryptedData) == 0 {
|
||||
return []byte{}
|
||||
}
|
||||
|
||||
// 预分配密钥字节数组(可全局缓存,避免每次创建)
|
||||
var keyBytes [4]byte // 栈上分配,比make更高效
|
||||
// 1. 栈上分配密钥字节数组(无GC压力,保留原优化)
|
||||
var keyBytes [4]byte
|
||||
binary.BigEndian.PutUint32(keyBytes[:], key)
|
||||
keyLen := len(keyBytes)
|
||||
|
||||
// 复用输出缓冲区:如果需要极致性能,可传入外部缓冲区
|
||||
decrypted := make([]byte, len(encryptedData))
|
||||
// 2. 从bytebufferpool获取池化缓冲区(替代make分配)
|
||||
buf := bytebufferpool.Get()
|
||||
defer bytebufferpool.Put(buf) // 函数结束自动归还缓冲区到池
|
||||
|
||||
// 3. 调整缓冲区长度,匹配待解密数据(避免扩容)
|
||||
buf.B = buf.B[:0] // 清空原有数据,保留底层数组
|
||||
if cap(buf.B) < len(encryptedData) {
|
||||
// 若缓冲区容量不足,直接扩容(bytebufferpool会自动管理)
|
||||
buf.B = make([]byte, len(encryptedData))
|
||||
} else {
|
||||
// 容量足够,直接调整长度
|
||||
buf.B = buf.B[:len(encryptedData)]
|
||||
}
|
||||
|
||||
// 4. 核心异或解密逻辑(直接操作buf.B,无额外内存分配)
|
||||
decrypted := buf.B
|
||||
for i, b := range encryptedData {
|
||||
decrypted[i] = b ^ keyBytes[i%keyLen]
|
||||
}
|
||||
|
||||
return decrypted
|
||||
// 5. 拷贝结果(关键:避免返回池化缓冲区,防止被后续调用覆盖)
|
||||
result := make([]byte, len(decrypted))
|
||||
copy(result, decrypted)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type Field struct {
|
||||
@@ -76,40 +77,60 @@ func (f *Field) Size(val reflect.Value, options *Options) int {
|
||||
return size
|
||||
}
|
||||
|
||||
// 预定义常用的order,避免重复判断
|
||||
var defaultOrder = binary.BigEndian
|
||||
|
||||
// packVal 优化版:减少反射开销+优化内存拷贝+优雅错误处理
|
||||
func (f *Field) packVal(buf []byte, val reflect.Value, length int, options *Options) (size int, err error) {
|
||||
// 1. 预缓存order,避免重复判断
|
||||
order := f.Order
|
||||
if options.Order != nil {
|
||||
if options != nil && options.Order != nil {
|
||||
order = options.Order
|
||||
}
|
||||
if f.Ptr {
|
||||
val = val.Elem()
|
||||
if order == nil {
|
||||
order = defaultOrder
|
||||
}
|
||||
|
||||
// 2. 处理指针类型:提前解引用,避免后续重复操作
|
||||
if f.Ptr {
|
||||
if !val.IsNil() {
|
||||
val = val.Elem()
|
||||
} else {
|
||||
return 0, fmt.Errorf("field %s is nil pointer", f.Name)
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 预解析类型,避免重复Resolve
|
||||
typ := f.Type.Resolve(options)
|
||||
kind := val.Kind()
|
||||
|
||||
// 4. 扁平化分支逻辑,减少嵌套
|
||||
switch typ {
|
||||
case Struct:
|
||||
return f.Fields.Pack(buf, val, options)
|
||||
|
||||
case Bool, Int8, Int16, Int32, Int64, Uint8, Uint16, Uint32, Uint64:
|
||||
size = typ.Size()
|
||||
if len(buf) < size {
|
||||
return 0, fmt.Errorf("buf size %d < required %d", len(buf), size)
|
||||
}
|
||||
|
||||
var n uint64
|
||||
switch f.kind {
|
||||
switch kind {
|
||||
case reflect.Bool:
|
||||
if val.Bool() {
|
||||
n = 1
|
||||
} else {
|
||||
n = 0
|
||||
}
|
||||
n = boolToUint64(val.Bool())
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
n = uint64(val.Int())
|
||||
default:
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
n = val.Uint()
|
||||
default:
|
||||
return 0, fmt.Errorf("unsupported kind %s for numeric type %s", kind, typ)
|
||||
}
|
||||
|
||||
// 扁平化数值写入逻辑
|
||||
switch typ {
|
||||
case Bool:
|
||||
if n != 0 {
|
||||
buf[0] = 1
|
||||
} else {
|
||||
buf[0] = 0
|
||||
}
|
||||
buf[0] = byte(n)
|
||||
case Int8, Uint8:
|
||||
buf[0] = byte(n)
|
||||
case Int16, Uint16:
|
||||
@@ -117,33 +138,90 @@ func (f *Field) packVal(buf []byte, val reflect.Value, length int, options *Opti
|
||||
case Int32, Uint32:
|
||||
order.PutUint32(buf, uint32(n))
|
||||
case Int64, Uint64:
|
||||
order.PutUint64(buf, uint64(n))
|
||||
order.PutUint64(buf, n)
|
||||
}
|
||||
|
||||
case Float32, Float64:
|
||||
size = typ.Size()
|
||||
if len(buf) < size {
|
||||
return 0, fmt.Errorf("buf size %d < required %d", len(buf), size)
|
||||
}
|
||||
|
||||
if kind != reflect.Float32 && kind != reflect.Float64 {
|
||||
return 0, fmt.Errorf("unsupported kind %s for float type %s", kind, typ)
|
||||
}
|
||||
n := val.Float()
|
||||
|
||||
switch typ {
|
||||
case Float32:
|
||||
order.PutUint32(buf, math.Float32bits(float32(n)))
|
||||
case Float64:
|
||||
order.PutUint64(buf, math.Float64bits(n))
|
||||
}
|
||||
|
||||
case String:
|
||||
switch f.kind {
|
||||
// 优化String类型:减少内存拷贝
|
||||
switch kind {
|
||||
case reflect.String:
|
||||
s := val.String()
|
||||
size = len(s)
|
||||
if len(buf) < size {
|
||||
return 0, fmt.Errorf("buf size %d < string length %d", len(buf), size)
|
||||
}
|
||||
// 用unsafe直接拷贝字符串到buf,避免[]byte(s)的内存分配
|
||||
copyStringToBuf(buf, s)
|
||||
|
||||
case reflect.Slice:
|
||||
if val.Type().Elem().Kind() != reflect.Uint8 {
|
||||
return 0, fmt.Errorf("unsupported slice type %s for String field", val.Type())
|
||||
}
|
||||
size = val.Len()
|
||||
copy(buf, []byte(val.String()))
|
||||
default:
|
||||
// TODO: handle kind != bytes here
|
||||
size = val.Len()
|
||||
if len(buf) < size {
|
||||
return 0, fmt.Errorf("buf size %d < bytes length %d", len(buf), size)
|
||||
}
|
||||
// 直接拷贝字节切片,避免冗余操作
|
||||
copy(buf, val.Bytes())
|
||||
|
||||
default:
|
||||
return 0, fmt.Errorf("unsupported kind %s for String type", kind)
|
||||
}
|
||||
|
||||
case CustomType:
|
||||
return val.Addr().Interface().(Custom).Pack(buf, options)
|
||||
// 优化反射断言:提前检查类型,避免panic
|
||||
if !val.CanAddr() {
|
||||
return 0, fmt.Errorf("custom type %s cannot take address", val.Type())
|
||||
}
|
||||
custom, ok := val.Addr().Interface().(Custom)
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("type %s does not implement Custom interface", val.Type())
|
||||
}
|
||||
return custom.Pack(buf, options)
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("no pack handler for type: %s", typ))
|
||||
// 替换panic为error,避免程序崩溃
|
||||
return 0, fmt.Errorf("no pack handler for type: %s", typ)
|
||||
}
|
||||
return
|
||||
|
||||
return size, nil
|
||||
}
|
||||
|
||||
// 辅助函数:bool转uint64,减少inline重复代码
|
||||
func boolToUint64(b bool) uint64 {
|
||||
if b {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// 辅助函数:unsafe拷贝字符串到buf,避免[]byte(s)的内存分配
|
||||
// 注意:仅在确定buf长度足够时使用
|
||||
func copyStringToBuf(buf []byte, s string) {
|
||||
// unsafe转换:字符串转字节切片,无内存分配
|
||||
src := *(*[]byte)(unsafe.Pointer(&struct {
|
||||
string
|
||||
cap int
|
||||
}{s, len(s)}))
|
||||
copy(buf, src)
|
||||
}
|
||||
|
||||
func (f *Field) Pack(buf []byte, val reflect.Value, length int, options *Options) (int, error) {
|
||||
|
||||
Reference in New Issue
Block a user