Go 是否可以通过关闭src来中断io.Copy?
代码示例:Go 是否可以通过关闭src来中断io.Copy?,go,io,Go,Io,代码示例: package main import ( "io" "os" "os/signal" "sync" "syscall" ) func main() { sigintCh := make(chan os.Signal, 1) signal.Notify(sigintCh, syscall.SIGINT, syscall.SIG
package main
import (
"io"
"os"
"os/signal"
"sync"
"syscall"
)
func main() {
sigintCh := make(chan os.Signal, 1)
signal.Notify(sigintCh, syscall.SIGINT, syscall.SIGTERM)
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
io.Copy(os.Stdout, os.Stdin)
}()
<-sigintCh
os.Stdin.Close()
wg.Wait()
}
主程序包
进口(
“io”
“操作系统”
“操作系统/信号”
“同步”
“系统调用”
)
func main(){
sigintCh:=make(信道操作信号,1)
signal.Notify(sigintCh、syscall.SIGINT、syscall.SIGTERM)
var wg sync.WaitGroup
工作组.添加(1)
go func(){
推迟工作组完成()
io.Copy(os.Stdout,os.Stdin)
}()
关闭os.Stdin
将导致io.Copy
在下次读取时返回错误已关闭的文件
(在CTRL-C
之后,尝试按Enter
)
如文件中所述:
关闭关闭文件,使其无法用于I/O
您不能通过关闭os.Stdin
强制EOF返回(或任何其他方式)。相反,您需要包装os.Stdin
并实现自己的Read
方法,该方法有条件地返回EOF
,或读取循环中的有限字节数
您可以在此线程上看到更多的讨论和可能的解决方法。您可以在不关闭源端的情况下中断io.Copy
,方法是传递一个io.Reader
,该读取器已用可取消的context.context
逻辑包装
修改上述goroutine,如下所示:
ctx, cancel := context.WithCancel(context.Background())
go func() {
defer wg.Done()
r := NewReader(ctx, os.Stdin) // wrap io.Reader to make it context-aware
_, err := io.Copy(os.Stdout, r)
if err != nil {
// context.Canceled error if interrupted
}
}()
<-sigintCh
cancel() // canceling context will interrupt io.Copy operation
Matt Ryer讨论了这一点—无需关闭io.Reader
—下面的详细信息。它不会中断读取调用。我不确定将问题隐藏在调用后面并“再来一次”是否是一个好主意goroutine.Infinite Read是一个奇怪的例子。这是我第一次遇到它。我认为逻辑应该清晰而简单。例如,goroutine with Read应该在应用程序退出时被忽略,或者应该有一个读取截止日期。是的-不想让答案复杂化-但是是的,你是对的,上面的内容不会抓住潜在原因的情况d永远阻塞。这是有解决办法的。当我处理使用net.Conn
的TCP应用程序时,这不仅是一个io.Reader
(和io.Writer
)-它还有setReadDailate
和SetWriteDeadline
。利用这些具有上述取消逻辑的功能-将取消任何读/写-即使在事实发生之后。@AlekseyBakin有趣的是os.Stdin
类型的*os.File
支持setReadDailate。在net.Conn io上使用它。读卡器允许提前取消-但是,如果我尝试在*os.File上使用它,它似乎不起作用(至少在MacOS上是这样):奇怪的是,在关闭它之后是否可以重新初始化os.Stdin
:从its开始,像这样简单地初始化Stdin=NewFile(uintpttr(syscall.Stdin),“/dev/Stdin”)
type readerCtx struct {
ctx context.Context
r io.Reader
}
func (r *readerCtx) Read(p []byte) (n int, err error) {
if err := r.ctx.Err(); err != nil {
return 0, err
}
return r.r.Read(p)
}
// NewReader gets a context-aware io.Reader.
func NewReader(ctx context.Context, r io.Reader) io.Reader {
return &readerCtx{ctx: ctx, r: r}
}