Fix for-range Issue Again in Go 1.22

  sonic0002        2024-11-21 01:03:04       1,061        1          English  中文  Tiếng Việt 

Với việc phát hành Go 1.22, nhóm Go đã giải quyết một vấn đề tồn tại lâu dài với phạm vi biến vòng lặp for-range, vốn là một cạm bẫy phổ biến đối với các nhà phát triển khi viết mã đồng thời. Cụ thể, vấn đề là biến vòng lặp trong vòng lặp for-range được tái sử dụng qua các lần lặp, dẫn đến hành vi không mong muốn khi có sự tham gia của các closure.

Vấn đề trước Go 1.22

Hãy xem xét ví dụ sau:

package forange

import "fmt"

func Do() {
    done := make(chan bool)
    values := []string{"a", "b", "c"}

    for _, v := range values {
        go func() {
            fmt.Println(v) // In ra các giá trị không mong muốn
            done <- true
        }()
    }

    for _ = range values {
        <-done
    }
}

Và có một tập tin go.mod như bên dưới

module playground

go 1.16

require github.com/ozgio/strutil v0.4.0

Trong các phiên bản Go trước 1.22, việc chạy mã này thường dẫn đến việc in ra cùng một giá trị (ví dụ: c) nhiều lần thay vì in từng giá trị trong values (a, b, c) như mong đợi. Điều này là do biến vòng lặp v được tái sử dụng qua các lần lặp, và các goroutine đã nắm giữ cùng một địa chỉ bộ nhớ.

Khắc phục trong Go 1.22

Go 1.22 đã giới thiệu một bản sửa lỗi cho hành vi này bằng cách làm cho biến vòng lặp hoạt động như thể nó được khai báo mới trong mỗi lần lặp. Điều này có nghĩa là mỗi closure giờ đây sẽ nắm giữ chính xác giá trị của v cho lần lặp tương ứng của nó.

Tuy nhiên, nếu bạn đã nâng cấp lên Go 1.22 và vẫn quan sát thấy hành vi cũ, có vấn đề, thủ phạm có thể là tập tin go.mod của bạn. Bản sửa lỗi chỉ có hiệu lực nếu tập tin go.mod chỉ định phiên bản Go là 1.22 trở lên. Sự phụ thuộc này là có chủ đích và cho phép các nhà phát triển giữ lại khả năng tương thích ngược với các hành vi cũ nếu cần.

Với go 1.22 được chỉ định trong go.mod của bạn và bản sửa lỗi được áp dụng, việc chạy chương trình trên sẽ in ra a, b, c một cách chính xác. Mỗi goroutine giờ đây nắm giữ giá trị chính xác của v cho lần lặp của nó.

Bài học kinh nghiệm

  • Luôn cập nhật: Luôn đọc ghi chú phát hành cho các phiên bản Go mới. Ghi chú phát hành Go 1.22 đã đề cập cụ thể đến thay đổi này và sự phụ thuộc của nó vào go.mod.
  • Sử dụng phiên bản go.mod chính xác: Nhiều tính năng ngôn ngữ Go được gắn với phiên bản go trong go.mod. Nếu bạn đang dựa vào các tính năng hoặc bản sửa lỗi mới, hãy đảm bảo phiên bản chính xác được chỉ định.
  • Kiểm thử kỹ lưỡng: Ngay cả sau khi nâng cấp Go, hãy đảm bảo rằng các chương trình của bạn hoạt động như mong đợi bằng cách chạy các bài kiểm tra toàn diện.

Tại sao sự phụ thuộc này là cần thiết?

Phương pháp phiên bản go.mod cho phép các nhóm áp dụng các bản sửa lỗi một cách tăng dần mà không làm hỏng các bản build hiện có. Bằng cách liên kết hành vi ngôn ngữ mới với phiên bản go trong go.mod, nhóm Go đảm bảo khả năng tương thích ngược đồng thời cho phép quá trình di chuyển mượt mà hơn cho các nhà phát triển.

Nếu bạn đã gặp phải những thách thức tương tự hoặc có những hiểu biết về cách điều này đã tác động đến quy trình làm việc của bạn, hãy chia sẻ trong phần bình luận!

BUG  GO  FOR RANGE  GO.MOD  GO 1.22 

       

  RELATED


  1 COMMENT


xieyonglin [Reply]@ 2024-11-21 06:43:57

Nice article?



  RANDOM FUN

Is this car fully tested?

Is this car fully tested? Or is it doing the Ice Bucket Challenge for ALS?