通道收到新值时终止旧Goroutine的代码问题及修复咨询
Hey, let's break down what's going wrong with your code and fix it to match your intended behavior!
The Root of the Problem
Your current code uses a single shared quit channel for all the create goroutines you launch. When you send true to this channel, there's no way to target the old goroutine specifically. Most of the time, the new goroutine you just started will hit the select statement first, grab that quit signal, and exit immediately—while the old goroutine is still stuck in its time.Sleep or business logic loop, never getting the stop command. That's why you're seeing the exact opposite of what you want.
The Fixed Code
We need to give each goroutine its own unique quit signal, and explicitly shut down the old one before starting a new one. Closing a channel is a clean, reliable way to do this (closing tells all receivers on that channel to wake up and exit immediately). Here's the revised code:
func Start() { go func() { var prevQuit chan struct{} // Keep track of the last goroutine's quit channel for nbp := range poll() { // Shut down the previous goroutine if it's still running if prevQuit != nil { close(prevQuit) } // Create a fresh quit channel for the new goroutine currentQuit := make(chan struct{}) prevQuit = currentQuit // Launch the new goroutine with its dedicated quit channel go create(nbp, currentQuit) } // Clean up the last running goroutine when poll() finishes if prevQuit != nil { close(prevQuit) } }() } func create(nbp map[string]string, quit chan struct{}) { defer fmt.Println("quiting this goroutine!") // Ensure we log exit every time for { select { case <-quit: // Channel was closed—exit immediately return default: // Run your core business logic here for k, v := range nbp { // ... your existing code } time.Sleep(3 * time.Second) } } }
Key Changes & Explanations
- Per-goroutine quit channels: Every new
creategoroutine gets its owncurrentQuitchannel, so we can precisely target which goroutine to shut down. - Closing channels instead of sending values: Closing a channel is a definitive stop signal—any goroutine waiting on that channel will wake up right away, even if it was in a
sleep. No more missed signals or race conditions! chan struct{}overchan bool: Since we only need a stop signal (no actual data to send),struct{}is the most lightweight choice (it uses zero memory).deferfor exit logging: Guarantees we print the quit message no matter how the goroutine exits, making debugging easier.
With this setup, every time poll() emits a new value, we first shut down the old running goroutine, then start the new one—exactly matching your intended behavior.
内容的提问来源于stack exchange,提问作者testing495

