chan是Go内存队列,非系统管道;os.Pipe()才对应Unix pipe,需手动close写端以触发EOF;for range ch要求仅发送方close,否则死锁。
是 Go 里最常被误称为“管道”的东西,但它
不是 Unix pipe
,也不涉及文件描述符、
或进程间通信。真要实现类似
的系统级管道,得用
或
配合
—— 两者完全不在一个抽象层。搞混就卡死、panic、读不到 EOF。
chan 是内存队列,不是系统 pipe
声明
创建的是 Go 运行时管理的内存结构,只在当前进程内有效。它没有 fd,不能传给子进程,也不能用
/
操作。
常见错误现象:
把
当成
直接丢进
—— 编译不过,类型不匹配
试图用
复制
—— 完全无效,
不是文件描述符
查 “Go 管道 IPC” 后写
想对接
—— 语义错位,该用
正确对应关系:
立即学习
“
go语言免费学习笔记(深入)
”;
→ goroutine 间同步/异步数据传递(如任务分发、结果收集)
→ 返回
读写端,可用于子进程 stdin/stdout 连接
→ 内存中的
/
对,适合在单进程内模拟流式行为
os.Pipe() 才是真 pipe,但要用对
返回一对
,本质是调用
系统调用,有真实 fd 和内核缓冲区。但它**不会自动 close**,必须手动关,否则子进程 hang 在 read 上。
典型用法(cmd1 | cmd2):
关键点:
必须在
前或同时触发,否则
永远等不到 EOF
不能只靠
自动关
—— Go 不会帮你关你没显式持有的
如果 cmd1 出错退出,
仍需 close,否则 cmd2 卡住
exec.Command + sh -c 是最稳的多级管道
写
时,别手撸三段
链 —— 容易漏关、goroutine 泄漏、超时无处理。
go语言参考手册 中文CHM版
Go 是一个开源的编程语言,它能让构造简单、可靠且高效的软件变得容易。本文给大家带来Go参考手册,需要的可以来下载! Go是从2007年末由Robert Griesemer, Rob Pike, Ken Thompson主持开发,后来还加入了Ian Lance Taylor, Russ Cox等人,并最终于2009年11月开源,在2012年早些时候发布了Go 1稳定版本。现在Go的开发已经是完全开放的,并且拥有一个活跃的社区。 Go 语言特色 简洁、快速、安全 并行、有趣、开源 内存管理、v数组安全、编译
下载
直接用 shell 解析最简单:
优势:
不用管 fd 生命周期、close 时机、goroutine 启停顺序
EOF、信号、退出码都由 shell 统一处理
Linux/macOS 一致;Windows 换
限制:
无法单独捕获中间命令(如
)的 stderr
沙箱环境禁用 shell 时不可用(此时才需手撸
)
chan 关闭和 range 的死锁陷阱
用
读 channel 时,如果没人关它,循环永远不退出 —— 这是并发链中最隐蔽的卡死点。
规则只有两条:
**仅最后一个发送方**调用
,且只调一次
接收方绝不能
,也绝不能在
外再读(比如
后又
)
错误示例:
但如果中间环节提前 return(比如 filter 拒绝空值后不发),而你又没确保下游能收尽,
就卡住 —— 这种逻辑边界比语法错误更难 debug。
chanos.Pipe()ls | grepos.Pipe()exec.CommandStdoutPipe()ch := make(chan int)os.Reados.Writechanio.Readerio.Copysyscall.Dup2chanchanmake(chan []byte)net.Connio.Pipe()chan Tos.Pipe()*os.Fileio.Pipe()io.Readerio.Writeros.Pipe()*os.Filepipe(2)pr, pw := os.Pipe()
cmd1 := exec.Command("ls")
cmd1.Stdout = pw
cmd2 := exec.Command("grep", "main")
cmd2.Stdin = pr
var b bytes.Buffer
cmd2.Stdout = &b
// 必须先 start,再 wait,顺序错就卡死
if err := cmd1.Start(); err != nil {
log.Fatal(err)
}
if err := cmd2.Start(); err != nil {
log.Fatal(err)
}
pw.Close() // 关闭写端,让 cmd2 收到 EOF
cmd1.Wait()
cmd2.Wait()
pw.Close()cmd1.Wait()cmd2cmd1.Wait()pw*os.Filepwps | grep go | awk '{print }'os.Pipe()cmd := exec.Command("sh", "-c", `ps aux | grep go | awk '{print $2}'`)
out, err := cmd.Output()
exec.Command("cmd", "/c", "...")grepos.Pipe()for range chclose(ch)close(ch)for range<-chfor rangech := make(chan int)
go func() {
for i := 0; i < 5; i++ {
ch <- i
}
close(ch) // ✅ 正确:发送完才关
}()
for v := range ch { // ✅ 正确:range 自动检测关闭
fmt.Println(v)
}
range