Đây là một ví dụ điển hình về chế độ worker & controller trong Go được viết bởi @Jimt, để trả lời cho " Có cách nào thú vị để tạm dừng và tiếp tục bất kỳ quy trình goroutine nào khác trong golang không? "
package main
import (
"fmt"
"runtime"
"sync"
"time"
)
// Possible worker states.
const (
Stopped = 0
Paused = 1
Running = 2
)
// Maximum number of workers.
const WorkerCount = 1000
func main() {
// Launch workers.
var wg sync.WaitGroup
wg.Add(WorkerCount + 1)
workers := make([]chan int, WorkerCount)
for i := range workers {
workers[i] = make(chan int)
go func(i int) {
worker(i, workers[i])
wg.Done()
}(i)
}
// Launch controller routine.
go func() {
controller(workers)
wg.Done()
}()
// Wait for all goroutines to finish.
wg.Wait()
}
func worker(id int, ws <-chan int) {
state := Paused // Begin in the paused state.
for {
select {
case state = <-ws:
switch state {
case Stopped:
fmt.Printf("Worker %d: Stopped\n", id)
return
case Running:
fmt.Printf("Worker %d: Running\n", id)
case Paused:
fmt.Printf("Worker %d: Paused\n", id)
}
default:
// We use runtime.Gosched() to prevent a deadlock in this case.
// It will not be needed of work is performed here which yields
// to the scheduler.
runtime.Gosched()
if state == Paused {
break
}
// Do actual work here.
}
}
}
// controller handles the current state of all workers. They can be
// instructed to be either running, paused or stopped entirely.
func controller(workers []chan int) {
// Start workers
for i := range workers {
workers[i] <- Running
}
// Pause workers.
<-time.After(1e9)
for i := range workers {
workers[i] <- Paused
}
// Unpause workers.
<-time.After(1e9)
for i := range workers {
workers[i] <- Running
}
// Shutdown workers.
<-time.After(1e9)
for i := range workers {
close(workers[i])
}
}
Nhưng mã này cũng có một vấn đề: Nếu bạn muốn xóa một kênh công nhân workers
khi worker()
thoát ra, thì sẽ xảy ra khóa chết.
Nếu bạn close(workers[i])
, lần sau bộ điều khiển ghi vào nó sẽ gây ra một sự hoảng sợ vì go không thể ghi vào một kênh đã đóng. Nếu bạn sử dụng một số mutex để bảo vệ nó, thì nó sẽ bị kẹt workers[i] <- Running
vì worker
không đọc bất cứ thứ gì từ kênh và ghi sẽ bị chặn và mutex sẽ gây ra khóa chết. Bạn cũng có thể cung cấp một bộ đệm lớn hơn cho kênh như một công việc xung quanh, nhưng nó không đủ tốt.
Vì vậy, tôi nghĩ cách tốt nhất để giải quyết vấn đề này là worker()
đóng kênh khi thoát ra, nếu bộ điều khiển tìm thấy một kênh bị đóng, nó sẽ nhảy qua nó và không làm gì cả. Nhưng tôi không thể tìm thấy cách kiểm tra kênh đã bị đóng hay chưa trong trường hợp này. Nếu tôi cố đọc kênh trong bộ điều khiển, bộ điều khiển có thể bị chặn. Vì vậy, hiện tại tôi rất bối rối.
Tái bút: Tôi đã cố gắng phục hồi cơn hoảng sợ đã tăng lên, nhưng nó sẽ đóng lại quy trình gây hoảng sợ. Trong trường hợp này nó sẽ là bộ điều khiển vì vậy nó không được sử dụng.
Tuy nhiên, tôi nghĩ rằng việc triển khai chức năng này trong phiên bản tiếp theo của cờ vây là rất hữu ích đối với đội cờ vây.