Skip to content

Commit bc9d5a1

Browse files
author
syd
committed
perf: decrease memory allocation
1 parent 59cc1ce commit bc9d5a1

File tree

6 files changed

+153
-39
lines changed

6 files changed

+153
-39
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import (
2424

2525
func main() {
2626
corpId := "企业ID"
27-
corpSecre := "secret"
27+
corpSecret := "secret"
2828
clt, err := sdk.NewClient(corpId, corpSecret)
2929
if err != nil {
3030
log.Fatalln(err)

buffer.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package wxworkfinancesdk
2+
3+
import (
4+
"bytes"
5+
"sync"
6+
)
7+
8+
var bufferPool = sync.Pool{
9+
New: func() any {
10+
return new(bytes.Buffer)
11+
},
12+
}
13+
14+
func BufferPool() *bytes.Buffer {
15+
return bufferPool.Get().(*bytes.Buffer)
16+
}
17+
18+
func BufferPoolRelease(v *bytes.Buffer) {
19+
v.Reset()
20+
bufferPool.Put(v)
21+
}
22+
23+
var readerPool = sync.Pool{
24+
New: func() any {
25+
return new(bytes.Reader)
26+
},
27+
}
28+
29+
func ReaderPool(bs []byte) *bytes.Reader {
30+
r := readerPool.Get().(*bytes.Reader)
31+
r.Reset(bs)
32+
return r
33+
}
34+
35+
func ReaderPoolRelease(r *bytes.Reader) {
36+
readerPool.Put(r)
37+
}

client.go

Lines changed: 81 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ package wxworkfinancesdk
77
// #include "WeWorkFinanceSdk_C.h"
88
import "C"
99
import (
10+
"bytes"
1011
"encoding/json"
12+
"errors"
1113
"io"
1214
"unsafe"
1315
)
@@ -30,8 +32,8 @@ func NewClient(corpId string, corpSecret string) (*Client, error) {
3032
}()
3133
retC := C.Init(ptr, corpIdC, corpSecretC)
3234
ret := int(retC)
33-
if ret == 0 {
34-
return nil, NewSDKErr(ret)
35+
if ret != 0 {
36+
return nil, NewSDKErr(ret, SDKInitErrMsg)
3537
}
3638
return &Client{
3739
ptr: ptr,
@@ -64,17 +66,20 @@ func (c *Client) GetChatData(seq uint64, limit uint64, proxy string, passwd stri
6466
}()
6567

6668
retC := C.GetChatData(c.ptr, C.ulonglong(seq), C.uint(limit), proxyC, passwdC, C.int(timeout), chatSlice)
67-
ret := int(retC)
68-
if ret != 0 {
69-
return nil, NewSDKErr(ret)
69+
if ret := int(retC); ret != 0 {
70+
return nil, NewSDKErr(ret, GetChatDataErrMsg)
71+
}
72+
buf := BufferPool()
73+
defer BufferPoolRelease(buf)
74+
c.GetContentFromSlice(chatSlice, buf)
75+
var data ChatDataResponse
76+
if err := json.NewDecoder(buf).Decode(&data); err != nil {
77+
return nil, errors.Join(err, NewSDKErr(-1, GetChatDataErrMsg))
7078
}
71-
buf := c.GetContentFromSlice(chatSlice)
72-
var data []ChatData
73-
err := json.Unmarshal(buf, &data)
74-
if err != nil {
75-
return nil, err
79+
if data.IsError() {
80+
return nil, data.Error
7681
}
77-
return data, nil
82+
return data.ChatDataList, nil
7883
}
7984

8085
// DecryptData 解析密文.企业微信自有解密内容
@@ -92,15 +97,18 @@ func (c *Client) DecryptData(encryptKey string, encryptMsg string) (Message, err
9297
}()
9398

9499
retC := C.DecryptData(encryptKeyC, encryptMsgC, msgSlice)
95-
ret := int(retC)
96-
if ret != 0 {
97-
return nil, NewSDKErr(ret)
100+
if ret := int(retC); ret != 0 {
101+
return nil, NewSDKErr(ret, DecryptErrMsg)
98102
}
99-
buf := c.GetContentFromSlice(msgSlice)
103+
buf := BufferPool()
104+
defer BufferPoolRelease(buf)
105+
c.GetContentFromSlice(msgSlice, buf)
106+
r := ReaderPool(buf.Bytes())
107+
defer ReaderPoolRelease(r)
100108
var baseMessage BaseMessage
101-
err := json.Unmarshal(buf, &baseMessage)
102-
if err != nil {
103-
return nil, err
109+
decoder := json.NewDecoder(r)
110+
if err := decoder.Decode(&baseMessage); err != nil {
111+
return nil, errors.Join(err, NewSDKErr(-1, DecryptErrMsg))
104112
}
105113
var msg Message
106114
if baseMessage.ActionType() == SWITCH_ACTION {
@@ -161,8 +169,11 @@ func (c *Client) DecryptData(encryptKey string, encryptMsg string) (Message, err
161169
msg = SphfeedMessage{}
162170
}
163171
}
164-
err = json.Unmarshal(buf, &msg)
165-
return msg, err
172+
r.Seek(0, 0)
173+
if err := decoder.Decode(&msg); err != nil {
174+
return nil, errors.Join(err, NewSDKErr(-1, DecryptErrMsg))
175+
}
176+
return msg, nil
166177
}
167178

168179
// GetMediaData 拉取媒体消息函数
@@ -174,7 +185,7 @@ func (c *Client) DecryptData(encryptKey string, encryptMsg string) (Message, err
174185
// @param [in] indexbuf 媒体消息分片拉取,需要填入每次拉取的索引信息。首次不需要填写,默认拉取512k,后续每次调用只需要将上次调用返回的outindexbuf填入即可。
175186
// @param [in] timeout 超时时间,单位秒
176187
// @return media_data 返回本次拉取的媒体数据.MediaData结构体.内容包括data(数据内容)/outindexbuf(下次索引)/is_finish(拉取完成标记)
177-
func (c *Client) GetMediaData(indexBuf string, sdkFileId string, proxy string, passwd string, timeout int) (*MediaData, error) {
188+
func (c *Client) GetMediaData(indexBuf string, sdkFileId string, proxy string, passwd string, timeout int, data *MediaData) error {
178189
indexBufC := C.CString(indexBuf)
179190
sdkFileIdC := C.CString(sdkFileId)
180191
proxyC := C.CString(proxy)
@@ -189,23 +200,22 @@ func (c *Client) GetMediaData(indexBuf string, sdkFileId string, proxy string, p
189200
}()
190201

191202
retC := C.GetMediaData(c.ptr, indexBufC, sdkFileIdC, proxyC, passwdC, C.int(timeout), mediaDataC)
192-
ret := int(retC)
193-
if ret != 0 {
194-
return nil, NewSDKErr(ret)
203+
if ret := int(retC); ret != 0 {
204+
return NewSDKErr(ret, GetMediaDataErrMsg)
195205
}
196-
return &MediaData{
197-
OutIndexBuf: C.GoString(C.GetOutIndexBuf(mediaDataC)),
198-
Data: C.GoBytes(unsafe.Pointer(C.GetData(mediaDataC)), C.GetDataLen(mediaDataC)),
199-
IsFinish: int(C.IsMediaDataFinish(mediaDataC)) == 1,
200-
}, nil
206+
data.OutIndexBuf = C.GoString(C.GetOutIndexBuf(mediaDataC))
207+
data.Data = C.GoBytes(unsafe.Pointer(C.GetData(mediaDataC)), C.GetDataLen(mediaDataC))
208+
data.IsFinish = int(C.IsMediaDataFinish(mediaDataC)) == 1
209+
return nil
201210
}
202211

203212
// DownloadMedia 下载MediaData
204-
func (c *Client) DownloadMedia(w io.Writer, sdkField string, proxy string, passwd string, timeout int) error {
213+
func (c *Client) DownloadMedia(w io.Writer, sdkFileId string, proxy string, passwd string, timeout int) error {
205214
var indexBuf string
215+
mediaData := MediaDataPool()
216+
defer MediaDataPoolRelease(mediaData)
206217
for {
207-
mediaData, err := c.GetMediaData(indexBuf, sdkField, proxy, passwd, timeout)
208-
if err != nil {
218+
if err := c.GetMediaData(indexBuf, sdkFileId, proxy, passwd, timeout, mediaData); err != nil {
209219
return err
210220
}
211221
w.Write(mediaData.Data)
@@ -217,7 +227,44 @@ func (c *Client) DownloadMedia(w io.Writer, sdkField string, proxy string, passw
217227
return nil
218228
}
219229

230+
// DownloadMediaZeroAlloc 下载MediaData zero mem alloc version
231+
func (c *Client) DownloadMediaZeroAlloc(w io.Writer, sdkFileId string, proxy string, passwd string, timeout int) error {
232+
var indexBuf string
233+
mediaData := MediaDataPool()
234+
defer MediaDataPoolRelease(mediaData)
235+
indexBufC := C.CString(indexBuf)
236+
sdkFileIdC := C.CString(sdkFileId)
237+
proxyC := C.CString(proxy)
238+
passwdC := C.CString(passwd)
239+
mediaDataC := C.NewMediaData()
240+
defer func() {
241+
C.free(unsafe.Pointer(indexBufC))
242+
C.free(unsafe.Pointer(sdkFileIdC))
243+
C.free(unsafe.Pointer(proxyC))
244+
C.free(unsafe.Pointer(passwdC))
245+
C.FreeMediaData(mediaDataC)
246+
}()
247+
for {
248+
retC := C.GetMediaData(c.ptr, indexBufC, sdkFileIdC, proxyC, passwdC, C.int(timeout), mediaDataC)
249+
if ret := int(retC); ret != 0 {
250+
return NewSDKErr(ret, GetMediaDataErrMsg)
251+
}
252+
indexBufC = C.GetOutIndexBuf(mediaDataC)
253+
l := C.GetDataLen(mediaDataC)
254+
bs := (*[1 << 30]byte)(unsafe.Pointer(C.GetData(mediaDataC)))[:l:l]
255+
// bs := C.GoBytes(unsafe.Pointer(C.GetData(mediaDataC)), C.GetDataLen(mediaDataC))
256+
w.Write(bs)
257+
if int(C.IsMediaDataFinish(mediaDataC)) == 1 {
258+
break
259+
}
260+
}
261+
return nil
262+
}
263+
220264
// GetContentFromSlice 转换C.struct_Slice_t为go bytes
221-
func (c Client) GetContentFromSlice(slice *C.struct_Slice_t) []byte {
222-
return C.GoBytes(unsafe.Pointer(C.GetContentFromSlice(slice)), C.GetSliceLen(slice))
265+
func (c Client) GetContentFromSlice(slice *C.struct_Slice_t, buf *bytes.Buffer) {
266+
l := C.GetSliceLen(slice)
267+
bs := (*[1 << 30]byte)(unsafe.Pointer(C.GetContentFromSlice(slice)))[:l:l]
268+
// buf.Write(C.GoBytes(unsafe.Pointer(C.GetContentFromSlice(slice)), C.GetSliceLen(slice)))
269+
buf.Write(bs)
223270
}

error.go

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,32 @@ import (
66

77
const (
88
// SDKErrMsg 错误消息
9-
SDKErrMsg = "sdk failed"
9+
// SDKInitErrMsg sdk 初始化失败
10+
SDKInitErrMsg = "sdk init failed"
11+
// GetChatDataErrMsg 调用 GetChatData API 失败
12+
GetChatDataErrMsg = "call GetChatData failed"
13+
// DecryptErrMsg 调用 DecryptMessage API 失败
14+
DecryptErrMsg = "call DecryptMessage API failed"
15+
// GetMediaDataErrMsg 调用 GetMediaData API 失败
16+
GetMediaDataErrMsg = "call GetMediaData API failed"
1017
)
1118

1219
// Error SDK Error结构体
1320
type Error struct {
1421
ErrCode int `json:"errcode,omitempty"` // 错误代码
1522
ErrMsg string `json:"errmsg,omitempty"` // 错误说明
23+
Hint string `json:"hint,omitempty"`
1624
}
1725

1826
// Error implement error interface
1927
func (e Error) Error() string {
20-
return fmt.Sprintf("%d:%s", e.ErrCode, e.ErrMsg)
28+
if e.Hint != "" {
29+
return fmt.Sprintf("errcode:%d, errmsg:%s, hint:%s", e.ErrCode, e.ErrMsg, e.Hint)
30+
}
31+
return fmt.Sprintf("errcode:%d, errmsg:%s", e.ErrCode, e.ErrMsg)
2132
}
2233

2334
// NewSDKErr 新建错误
24-
func NewSDKErr(code int) Error {
25-
return Error{ErrCode: code, ErrMsg: SDKErrMsg}
35+
func NewSDKErr(code int, msg string) Error {
36+
return Error{ErrCode: code, ErrMsg: msg}
2637
}

libWeWorkFinanceSdk_C.so

14.6 MB
Binary file not shown.

media.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,27 @@
11
package wxworkfinancesdk
22

3+
import "sync"
4+
35
// MediaData 媒体消息结构体
46
type MediaData struct {
57
OutIndexBuf string `json:"outindexbuf,omitempty"` // 消息分片索引信息
68
IsFinish bool `json:"is_finish,omitempty"` //
79
Data []byte `json:"data,omitempty"` // 媒体数据内通
810
}
11+
12+
var mediaDataPool = sync.Pool{
13+
New: func() any {
14+
return new(MediaData)
15+
},
16+
}
17+
18+
func MediaDataPool() *MediaData {
19+
return mediaDataPool.Get().(*MediaData)
20+
}
21+
22+
func MediaDataPoolRelease(m *MediaData) {
23+
m.OutIndexBuf = ""
24+
m.IsFinish = false
25+
m.Data = nil
26+
mediaDataPool.Put(m)
27+
}

0 commit comments

Comments
 (0)