golang:`os.Stdin.Read`不处理仅由EOF组成的输入吗?

问题描述

我是writing只猫,在接收到第一个字节时超时。除了无法处理echo -n之外,我都可以使用它:

❯ echo -n | time possiblycat 1000  # 1000 is the timeout in milliseconds                                                                                        
possiblycat 1000  0.00s user 0.00s system 0% cpu 1.008 total; max RSS 1864

cat本身对此没有问题;它会注意到EOF并立即退出:

❯ echo -n | time cat                                                                                                      
cat  0.00s user 0.00s system 71% cpu 0.003 total; max RSS 664

这是possiblycat的全部来源:

package main

import (
    "io"
    "io/ioutil"
    "os"
    "strconv"
    "time"
)

func main() {
    wait := 10
    if len(os.Args) >= 2 {
        waitDummy,err := strconv.Atoi(os.Args[1])
        if err != nil {
            panic(err)
        }
        wait = waitDummy
    }

    b := make(chan byte,1)
    go scan(b)

    select {
    case res := <-b:
        inBytes,err := ioutil.ReadAll(os.Stdin)
        if err != nil {
            panic(err)
        }
        stdin := append([]byte{res},inBytes...)
        _,err2 := os.Stdout.Write(stdin)
        if err2 != nil {
            panic(err2)
        }
    case <-time.After(time.Duration(wait) * time.Millisecond):
        os.Exit(1)
    }
}

func scan(out chan byte) {
    var b []byte = make([]byte,1)
    _,err := os.Stdin.Read(b)
    if err == io.EOF {
        return
    } else if err != nil {
        panic(err)
    }
    out <- b[0]
}

相关:

解决方法

os.Stdin.Read返回EOF时,退出运行在其goroutine中的scan函数。

但是,并没有采取任何措施告诉主goroutine所有输入都已处理。它正在等待通道b上的数据或超时。由于b上没有数据,因此达到了超时时间。

要正确处理此问题,err == io.EOF情况应向主goroutine发出信号,表明没有更多工作要做。一种常见的模式(但肯定不是唯一的一种)是有一个done频道,指示所有工作都已完成。

  done := make(chan bool,1)
  go scan(b,done)

  select {
  case res := <-b:
    ...
  case <-done:
    os.Exit(1)
  case <-time.After(time.Duration(wait) * time.Millisecond):
    os.Exit(1)
  }
}

func scan(out chan byte,done chan bool) {
  var b []byte = make([]byte,1)
  _,err := os.Stdin.Read(b)
  if err == io.EOF {
    fmt.Println("got EOF,exiting")
    done <- true
    return
  } else if err != nil {
  ...
}

另一种(甚至更简单的)替代方法是在完成后简单地关闭数据通道:

func scan(out chan byte) {
  var b []byte = make([]byte,exiting")
    close(out)
    return
  } else if err != nil {
    panic(err)
  }
  out <- b[0]
}

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...