You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go并发编程实现多函数并行报send on closed channel错误求助

Go并发终端程序panic问题修复

问题根因

你的代码触发send on closed channel panic有三个核心错误:

  • main函数里过早关闭通道:启动3个goroutine后立刻执行了close(inChan),此时goroutine刚启动还在运行,后续getInputs往已经关闭的通道写数据直接触发panic。
  • 通道使用逻辑错误:你用同一个无缓冲通道同时给showTime和showInputs传值,无缓冲通道的消息只会被其中一个消费者随机取走,会出现时间打印和输入响应互相抢消息的问题。
  • 定时逻辑不符合需求:showTime现有逻辑是等通道消息才打印时间、睡一秒,根本做不到每秒自动打印时间的设计目标——你之前看到的连续3秒打印时间,本质是从已关闭通道读取零值触发的循环,不是正常的定时逻辑。

修复思路

  • 把打印时间的逻辑改成独立的ticker定时触发,不需要依赖输入通道传值,用独立的退出信号控制它终止
  • 不要在main里提前关通道,等所有逻辑跑完(收到done信号)再做资源回收
  • 输入通道只负责传递用户输入内容,单独开goroutine处理输入响应,和定时打印时间逻辑完全解耦
  • 用独立的done通道做全局退出广播,收到"done"输入时通知所有goroutine退出,再等待所有goroutine收尾后退出程序

修正后可运行代码

package main

import (
	"bufio"
	"fmt"
	"os"
	"sync"
	"time"
)

// getInputs 监听用户输入,非空内容写入输入通道
func getInputs(ch chan<- string, wg *sync.WaitGroup) {
	defer wg.Done()
	scanner := bufio.NewScanner(os.Stdin)
	for {
		// 逐行读取用户输入,比Scanln更稳定,支持带空格的输入
		if !scanner.Scan() {
			break
		}
		input := scanner.Text()
		if input != "" {
			ch <- input
			// 收到done指令就退出输入监听
			if input == "done" {
				return
			}
		}
	}
}

// showInputs 处理用户输入的指令响应
func showInputs(inCh <-chan string, done chan<- struct{}, wg *sync.WaitGroup) {
	defer wg.Done()
	for {
		msg := <-inCh
		switch msg {
		case "dog":
			fmt.Println("YEP thats a dog!")
		case "done":
			// 收到done信号,通知所有协程退出
			close(done)
			return
		default:
			fmt.Printf("Received your input: %s\n", msg)
		}
	}
}

// showTime 每秒打印当前时间,收到退出信号就终止
func showTime(done <-chan struct{}, wg *sync.WaitGroup) {
	defer wg.Done()
	// 初始化每秒触发的ticker
	ticker := time.NewTicker(time.Second)
	defer ticker.Stop()

	// 启动后立刻打印一次当前时间
	fmt.Println(time.Now().String())
	for {
		select {
		case <-ticker.C:
			fmt.Println(time.Now().String())
		case <-done:
			return
		}
	}
}

func main() {
	var wg sync.WaitGroup
	inChan := make(chan string)
	done := make(chan struct{}) // 全局退出信号通道

	wg.Add(3)
	go showTime(done, &wg)
	go showInputs(inChan, done, &wg)
	go getInputs(inChan, &wg)

	// 等待所有协程收尾
	wg.Wait()
	fmt.Println("The End!")
}

代码运行说明

  • 程序启动后会立刻打印当前时间,之后每秒自动刷新打印时间
  • 输入任意文本回车,程序会回显收到的输入;输入dog会触发固定响应YEP thats a dog!
  • 输入done回车后,所有运行中的goroutine会收到退出信号,完成收尾后打印The End!正常退出,不会触发panic

内容的提问来源于stack exchange,提问作者Kiarash Salooti

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 20:27:27