[Go] Goroutine Prevent Leak
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 goroutinetronggolang
Ví dụ 1;
- Để thành công trong việc giảm thiểu leak trong goroutine thì dùng channelgiữa cácgoroutine cha và con. Bởi theo quy định, signal luôn luôn chỉ đọc, vàgoroutinecha passchannelđến goroutine con. Khichannelclose, 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 funcPrevent(). Nhận vào 2 parameter và return 1 parameter
- (2) Trong line này, dùng for-selectpattern, trong case<-donelà kiểm trachannelcó được báo tín hiệu chưa, nếu có thì sẽ returngoroutine
- (3) Tạo một goroutinekhác, mục đích để canceldoWorksau 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.
 
- (1) 
- Kêt quả:
Canceling doWork goroutine...
done in work
doWork exited.
Done.
- Như kết quả, mặc dù trong function doWork()truyềnstring=nilnhưng goroutine vẫn có thể exit, và clean-up resource.
- Để có thể join 2 goroutinelại với nhau, tạo thêm 1goroutinethứ 3, mục đích đểcancelfuncdoWork()sau 1 giây.
Ví dụ 2:
- Trong ví dụ này, thử nghiệm thêm trường hợp đó là nhận valuetừ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.
 
- (1) khi dòng này xuất hiện thì 
- 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 sendrandom numberra bên ngoài, nhưng có cóchannelread. Có nghĩa không có cách nào đểstop goroutineđang chạyrandom-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, 1goroutinethứ 3 =>terminates goroutinethành công
 
- Như ví dụ trước, cũng tạo thêm 1 
- 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.
Liên Hệ
- facebook: https://www.facebook.com/phucducdev/
- group: https://www.facebook.com/groups/575250507328049
- gmail: ducnp09081998@gmail.com
- linkedin: https://www.linkedin.com/in/phucducktpm/
- hashnode: https://hashnode.com/@OpenDev
- telegram: https://t.me/OpenDevGolang
All rights reserved
 
  
 