From 0b504aafc1353887f02c971fb5f1011bc056eb70 Mon Sep 17 00:00:00 2001 From: Hau Nguyen Date: Sun, 5 Mar 2023 17:23:25 +0700 Subject: [PATCH] feat: add sync pool --- docs/2022-07-10-bootstrap-go.html | 72 +++++++++++++++++++++++++++++-- posts/2022-07-10-bootstrap-go.md | 49 ++++++++++++++++++++- 2 files changed, 116 insertions(+), 5 deletions(-) diff --git a/docs/2022-07-10-bootstrap-go.html b/docs/2022-07-10-bootstrap-go.html index d1b4aaf..7442b24 100644 --- a/docs/2022-07-10-bootstrap-go.html +++ b/docs/2022-07-10-bootstrap-go.html @@ -307,6 +307,45 @@ internal Please don't use external libs for WorkerPool, I don't want to deal with dependency hell.

+

+ Use + sync.Pool when + need to reuse object, mainly for bytes.Buffer +

+

Example:

+
+
var bufPool = sync.Pool{
+	New: func() any {
+		return new(bytes.Buffer)
+	},
+}
+
+func MarshalWithoutEscapeHTML(v any) ([]byte, error) {
+	b, ok := bufPool.Get().(*bytes.Buffer)
+	if !ok {
+		return nil, ErrBufPoolNotBytesBuffer
+	}
+
+	b.Reset()
+	defer bufPool.Put(b)
+
+	encoder := json.NewEncoder(b)
+	encoder.SetEscapeHTML(false)
+	if err := encoder.Encode(v); err != nil {
+		return nil, err
+	}
+
+	result := make([]byte, b.Len())
+	copy(result, b.Bytes())
+	return result, nil
+}
+

gin.Context when pass context from handler layer to service layer, use gin.Context.Request.Context() instead.

+

Remember to free resources after parse multipart form:

+
+
defer func() {
+    if err := c.Request.MultipartForm.RemoveAll(); err != nil {
+        fmt.Println(err)
+    }
+}()
+

go-redis/redis_rate

- rate if you want rate limiter locally in your single instance of service. - redis_rate if you want rate limiter distributed across all your instances - of service. + rate if you want rate limiter locally in your single + instance of service. redis_rate if you want rate limiter + distributed across all your instances of service.

*.go >Three bugs in the Go MySQL Driver +
  • + Fixing Memory Exhaustion Bugs in My Golang Web App +
  • +
  • + Prevent Logging Secrets in Go by Using Custom Types +
  • +
  • + Speed Up GoMock with Conditional Generation +
  • diff --git a/posts/2022-07-10-bootstrap-go.md b/posts/2022-07-10-bootstrap-go.md index ff81a73..b5d5f9d 100644 --- a/posts/2022-07-10-bootstrap-go.md +++ b/posts/2022-07-10-bootstrap-go.md @@ -147,6 +147,38 @@ if err := eg.Wait(); err != nil { Please don't use external libs for WorkerPool, I don't want to deal with dependency hell. +### Use [sync.Pool](https://pkg.go.dev/sync#Pool) when need to reuse object, mainly for `bytes.Buffer` + +Example: + +```go +var bufPool = sync.Pool{ + New: func() any { + return new(bytes.Buffer) + }, +} + +func MarshalWithoutEscapeHTML(v any) ([]byte, error) { + b, ok := bufPool.Get().(*bytes.Buffer) + if !ok { + return nil, ErrBufPoolNotBytesBuffer + } + + b.Reset() + defer bufPool.Put(b) + + encoder := json.NewEncoder(b) + encoder.SetEscapeHTML(false) + if err := encoder.Encode(v); err != nil { + return nil, err + } + + result := make([]byte, b.Len()) + copy(result, b.Bytes()) + return result, nil +} +``` + ## External libs ### No need `vendor` @@ -202,6 +234,16 @@ prototool is deprecated, and buf can generate, lint, format as good as prototool Don't use `gin.Context` when pass context from handler layer to service layer, use `gin.Context.Request.Context()` instead. +Remember to free resources after parse multipart form: + +```go +defer func() { + if err := c.Request.MultipartForm.RemoveAll(); err != nil { + fmt.Println(err) + } +}() +``` + ### If you want log, just use [uber-go/zap](https://github.com/uber-go/zap) It is fast! @@ -342,8 +384,8 @@ stringer -type=Drink ### Don't waste your time rewrite rate limiter if your use case is simple, use [rate](https://pkg.go.dev/golang.org/x/time/rate) or [go-redis/redis_rate](https://github.com/go-redis/redis_rate) -rate if you want rate limiter locally in your single instance of service. -redis_rate if you want rate limiter distributed across all your instances of service. +**rate** if you want rate limiter locally in your single instance of service. +**redis_rate** if you want rate limiter distributed across all your instances of service. ### Replace `go fmt`, `goimports` with [mvdan/gofumpt](https://github.com/mvdan/gofumpt). @@ -370,3 +412,6 @@ fieldalignment -fix ./internal/business/*.go - [Functional options for friendly APIs](https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis) - [Google Go Style](https://google.github.io/styleguide/go/index) - [Three bugs in the Go MySQL Driver](https://github.blog/2020-05-20-three-bugs-in-the-go-mysql-driver/) +- [Fixing Memory Exhaustion Bugs in My Golang Web App](https://mtlynch.io/notes/picoshare-perf/) +- [Prevent Logging Secrets in Go by Using Custom Types](https://www.commonfate.io/blog/prevent-logging-secrets-in-go-by-using-custom-types) +- [Speed Up GoMock with Conditional Generation](https://jonwillia.ms/2019/12/22/conditional-gomock-mockgen)