- vừa được xem lúc

[Go] Goroutine Prevent Leak

0 0 28

Người đăng: Open Dev

Theo Viblo Asia

Goroutine Leak, và debug resource: https://viblo.asia/p/golang-leaks-in-goroutine-and-debug-resource-3kY4g5q0LAe

prevent-leak

  • Trong ví dụ trước đã nói về leak cũng như debug resource bằng pprof
  • Thì bài viết này hỗ trợ làm sao để không bị leak khi sử dụng goroutine trong golang

Ví dụ 1;

  • Để thành công trong việc giảm thiểu leak trong goroutine thì dùng channel giữa các goroutine cha và con. Bởi theo quy định, signal luôn luôn chỉ đọc, và goroutine cha pass channel đến goroutine con. Khi channel close, nó sẽ close cả goroutine con.
  • Code example:
func Preven() { doWork := func(done <-chan interface{}, strings <-chan string) <-chan interface{} { // (1) terminated := make(chan interface{}) go func() { defer fmt.Println("doWork exited.") defer close(terminated) for { select { case s := <-strings: // Do something interesting fmt.Println(s) case <-done: // (2) fmt.Println("done in work") return } } }() return terminated } done := make(chan interface{}) terminated := doWork(done, nil) go func() { // (3) // Cancel the operation after 1 second. time.Sleep(1 * time.Second) fmt.Println("Canceling doWork goroutine...") close(done) }() <-terminated // (4) fmt.Println("Done.")
}
  • Ghi chú:
    • (1) doWork() là một function bình thường, khai báo trong func Prevent(). Nhận vào 2 parameter và return 1 parameter
    • (2) Trong line này, dùng for-select pattern, trong case <-done là kiểm tra channel có được báo tín hiệu chưa, nếu có thì sẽ return goroutine
    • (3) Tạo một goroutine khác, mục đích để cancel doWork sau thời gian 1 giây
    • (4) Để merge 2 goroutine lại với nhau, tiếp tục process những phần khác.
  • Kêt quả:
Canceling doWork goroutine...
done in work
doWork exited.
Done.
  • Như kết quả, mặc dù trong function doWork() truyền string=nil nhưng goroutine vẫn có thể exit, và clean-up resource.
  • Để có thể join 2 goroutine lại với nhau, tạo thêm 1 goroutine thứ 3, mục đích để cancel func doWork() sau 1 giây.

Ví dụ 2:

  • Trong ví dụ này, thử nghiệm thêm trường hợp đó là nhận value từ channel
  • Code example:
func LeakReceive() { newRandStream := func() <-chan int { randStream := make(chan int) go func() { defer fmt.Println("newRandStream closure exited.") // (1) defer close(randStream) for { randStream <- rand.Int() } }() return randStream } randStream := newRandStream() fmt.Println("3 random ints:") for i := 1; i <= 3; i++ { fmt.Printf("%d: %d\n", i, <-randStream) }
}
  • Ghi chú:
    • (1) khi dòng này xuất hiện thì goroutine đã được remove thành công.
  • Kêt quả:
3 random ints:
1: 5577006791947779410
2: 8674665223082153551
3: 6129484611666145821
  • Trong print out, không có hàm defer fmt.Println, điều này đồng nghĩa nó không được thực thi => leak.

  • Sau khi 3 lần lặp, goroutine đã bị block và cố gắng send random number ra bên ngoài, nhưng có có channel read. Có nghĩa không có cách nào để stop goroutine đang chạy random-number

  • Giải pháp, code:

func PreventLeakReceive() { newRandStream := func(done <-chan interface{}) <-chan int { randStream := make(chan int) go func() { defer fmt.Println("newRandStream closure exited.") defer close(randStream) for { select { case randStream <- rand.Int(): case <-done: return } } }() return randStream } done := make(chan interface{}) randStream := newRandStream(done) fmt.Println("3 random ints:") for i := 1; i <= 3; i++ { fmt.Printf("%d: %d\n", i, <-randStream) } close(done) // Simulate ongoing work time.Sleep(1 * time.Second)
}
  • Ghi Chú:
    • Như ví dụ trước, cũng tạo thêm 1 channle, 1 goroutine thứ 3 => terminates goroutine thành công
  • Kết quả:
3 random ints:
1: 5577006791947779410
2: 8674665223082153551
3: 6129484611666145821
newRandStream closure exited.
  • Như đã nhìn thấy, goroutine thực sữ đã được clean-up.

Bình luận

Bài viết tương tự

- vừa được xem lúc

gRPC - Nó là gì và có nên sử dụng hay không?

Nhân một ngày rảnh rỗi, mình ngồi đọc lại RPC cũng như gRPC viết lại để nhớ lâu hơn. Vấn đề là gì và tại sao cần nó .

0 0 131

- vừa được xem lúc

Embedded Template in Go

Getting Start. Part of developing a web application usually revolves around working with HTML as user interface.

0 0 56

- vừa được xem lúc

Tạo Resful API đơn giản với Echo framework và MySQL

1. Giới thiệu.

0 0 60

- vừa được xem lúc

Sử dụng goquery trong golang để crawler thông tin các website Việt Nam bị deface trên mirror-h.org

. Trong bài viết này, mình sẽ cùng mọi người khám phá một package thu thập dữ liệu có tên là goquery của golang. Mục tiêu chính của chương trình crawler này sẽ là lấy thông tin các website Việt Nam bị deface (là tấn công, phá hoại website, làm thay đổi giao diện hiển thị của một trang web, khi người

0 0 237

- vừa được xem lúc

Tạo ứng dụng craw dữ liệu bing với Golang, Mysql driver

Chào mọi người . Lâu lâu ta lại gặp nhau 1 lần, để tiếp tục series chia sẻ kiến thức về tech, hôm nay mình sẽ tìm hiểu và chia sẻ về 1 ngôn ngữ đang khá hot trong cộng đồng IT đó là Golang.

0 0 75

- vừa được xem lúc

Golang: Rest api and routing using MUX

Routing with MUX. Let's create a simple CRUD api for a blog site. # All . GET articles/ .

0 0 54