gpt4 book ai didi

go - 如何在不阅读的情况下检查 channel 是否关闭?

转载 作者:行者123 更新时间:2023-12-01 22:24:45 25 4
gpt4 key购买 nike

这是@Jimt 编写的 Go 中工作人员和 Controller 模式的一个很好的示例,以回答
"Is there some elegant way to pause & resume any other goroutine in golang? "

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])
}
}

但是这段代码也有一个问题:如果你想在 workers 中移除一个工作 channel 当 worker()退出,死锁发生。

如果您 close(workers[i]) ,下次 Controller 写入它会导致 panic ,因为 go 无法写入关闭的 channel 。如果你使用一些互斥锁来保护它,那么它会卡在 workers[i] <- Running上。自从 worker没有从 channel 读取任何内容并且写入将被阻塞,并且互斥锁将导致死锁。您也可以为 channel 提供更大的缓冲区作为解决方法,但这还不够好。

所以我认为解决这个问题的最好方法是 worker()退出时关闭 channel ,如果 Controller 发现 channel 关闭,它将跳过它并且什么都不做。但是在这种情况下,我找不到如何检查 channel 是否已关闭。如果我尝试读取 Controller 中的 channel , Controller 可能被阻塞。所以我现在很困惑。

PS:恢复引发的 panic 是我尝试过的,但它会关闭引发 panic 的goroutine。在这种情况下,它将是 Controller ,所以没有用。

不过,我认为 Go 团队在下一个版本的 Go 中实现这个功能是有用的。

最佳答案

没有办法编写一个安全的应用程序,您需要知道一个通​​道是否打开而不与它交互。

做你想做的事情的最好方法是使用两个 channel ——一个用于工作,一个用于表明改变状态的愿望(以及如果这很重要,那么状态改变的完成)。

channel 很便宜。复杂的设计重载语义不是。

[还]

<-time.After(1e9)

是一种非常令人困惑和不明显的写作方式
time.Sleep(time.Second)

保持简单,每个人(包括你)都能理解它们。

关于go - 如何在不阅读的情况下检查 channel 是否关闭?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60767115/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com