feat(config): 添加超时空地图配置和时间地图查询功能 新增IsTimeSpace字段用于标识地图是否为超时空地图, 添加TimeMap API接口支持查询超时空地图配置 perf(socket): 优化XORDecryptU解密函数减少内存分配 基于bytebufferpool实现缓冲区池化,大幅降低高频调用下的 内存分配和GC压力,提升性能表现 refactor(utils): 优化packVal序列化函数提升性能和稳定性 减少反射开销,
This commit is contained in:
@@ -13,6 +13,8 @@ go tool pprof -http :8081 "http://127.0.0.1:9909/debug/pprof/profile"
|
||||
|
||||
go tool pprof -http :8081 "http://202.189.15.67:62672/debug/pprof/profile"
|
||||
go tool pprof -http :8081 "http://8.162.8.203:9909/debug/pprof//profile"
|
||||
go tool pprof -http :8081 "http://8.162.23.87:9909/debug/pprof//profile"
|
||||
|
||||
详情查看 [文档](./docs)
|
||||
|
||||
- [战斗](./docs/battle.md)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -3,6 +3,9 @@ package admin
|
||||
import (
|
||||
"blazing/cool"
|
||||
"blazing/modules/config/service"
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
type MapController struct {
|
||||
@@ -20,3 +23,13 @@ func init() {
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
type TimeMapReq struct {
|
||||
g.Meta `path:"/timemap" method:"POST"`
|
||||
}
|
||||
|
||||
func (this *MapController) TimeMap(ctx context.Context, req *TimeMapReq) (res *cool.BaseRes, err error) {
|
||||
res = &cool.BaseRes{}
|
||||
res.Data = service.NewMapService().GetTimeMap()
|
||||
return res, nil
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@ type MapConfig struct {
|
||||
MapID uint32 `gorm:"not null;primaryKey;comment:'地图唯一ID(主键)'" json:"map_id" description:"地图ID"`
|
||||
|
||||
WeatherType []uint32 `gorm:"type:int[];comment:'天气类型( 1-雨天,2-雪天)'" json:"weather_type"`
|
||||
//是否超时空
|
||||
IsTimeSpace int `gorm:"type:int;default:0;comment:'是否超时空'" json:"is_time_space"`
|
||||
|
||||
// 掉落物配置
|
||||
DropItemIds []uint32 `gorm:"type:int[];comment:'掉落物IDs" json:"drop_item_ids"`
|
||||
|
||||
@@ -29,3 +29,12 @@ func (s *MapService) GetData(p1 uint32) (ret *model.MapConfig) {
|
||||
return
|
||||
|
||||
}
|
||||
func (s *MapService) GetTimeMap() (ret []model.MapConfig) {
|
||||
//cacheKey := strings.Join([]string{fmt.Sprintf("%d", p1), fmt.Sprintf("%d", p2)}, ":")
|
||||
m := dbm_notenable(s.Model)
|
||||
|
||||
m.Where(`is_time_space`, 1).Scan(&ret)
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user