|
Trong ví dụ trước, chúng ta đã thấy cách quản lý trạng thái bộ đếm đơn giản bằng cách sử dụng atomic operations. Đối với trạng thái phức tạp hơn, chúng ta có thể sử dụng một mutex để truy cập dữ liệu một cách an toàn giữa nhiều goroutines. |
![]()
package main |
import ( "fmt" "sync" ) |
|
|
Struct Container chứa một map các counters; vì chúng ta muốn
cập nhật nó đồng thời từ nhiều goroutines, chúng ta
thêm một |
type Container struct { mu sync.Mutex counters map[string]int } |
|
Khoá mutex trước khi truy cập |
func (c *Container) inc(name string) { |
c.mu.Lock() defer c.mu.Unlock() c.counters[name]++ } |
|
|
Lưu ý rằng ta có thể sử dụng giá trị mặc định là không của mutex, do đó không cần phải khởi tạo nó. |
func main() { c := Container{ |
counters: map[string]int{"a": 0, "b": 0}, } |
|
var wg sync.WaitGroup |
|
|
Hàm sau đây làm tăng giá trị của một biến đếm trong một vòng lặp. |
doIncrement := func(name string, n int) {
for i := 0; i < n; i++ {
c.inc(name)
}
wg.Done()
}
|
|
Thực thi đồng thời nhiều goroutines; lưu ý rằng
chúng đều truy cập vào cùng một |
wg.Add(3)
go doIncrement("a", 10000)
go doIncrement("a", 10000)
go doIncrement("b", 10000)
|
|
Chờ cho các goroutines chạy xong. |
wg.Wait()
fmt.Println(c.counters)
}
|
|
Chạy chương trình sẽ cho thấy rằng các biến đếm được cập nhật như mong đợi. |
$ go run mutexes.go map[a:20000 b:10000] |
|
Tiếp theo chúng ta sẽ xem xét việc thực hiện cùng một tác vụ quản lý trạng thái sử dụng goroutines và channels. |
Ví dụ tiếp theo: Stateful Goroutines.