dtpf76658 2017-04-25 12:26
浏览 145
已采纳

想要使用通道从os.Stdin写入os.Stdout

/* Want to write from os.Stdin to os.Stdout(fmt.Println() in below code) using channels*/
package main
import (
    "fmt"
    "io"
    "os"
    "bufio"
)

type message []byte
/* Function to run the groutine to run for stdin read */
func read (r io.Reader) <-chan message{
    lines := make (chan message)
    go func() {
        defer close(lines)
        scan := bufio.NewScanner(r)
        for scan.Scan() {
            lines <- message(scan.Bytes())
        }   
    }() 
    return lines
}


func main() {
    mes := make (chan message, 1)
    sig := make (chan bool)
    ch := read (os.Stdin) //Reading from Stdin
    for {
        select {
            case anu := <-mes:
                fmt.Println("Message to stdout")
                fmt.Println(string(anu)) //Writing to Stdout
            case mes <- <-ch:
                fmt.Println("Message to channel 2")
                continue
        }   
    }   
    <-sig

/*
The O/P is :

go run writetochan.go 
Golang
Message to channel 2
Fun     <<< Delayed O/P golang means after putting one more 
            message only we are getting First message
Message to stdout
Golang


Expected O/P:
go run writetochan.go 
Golang
Message to channel 2
Message to stdout
Golang
Fun
Message to channel 2

*/
}

Want to achieve the O/P shown above.

We are writing from one channel which reads all the stdin from the user and then writes to the stdout. Channel read is happening in goroutine. A dummy channel is formed (sig) so that we can run it indefinitely (Just for now).

  • 写回答

1条回答 默认 最新

  • drl959975 2017-04-25 18:35
    关注

    The problem is that you have two channel operations in your second select case. Select only prevents the outer operation from blocking. Thus the <-ch call is evaluated immediately, and doesn't have the blocking protection of the select, so the entire select statement blocks until something else is received on that channel (which requires another input so read() can send again on that channel).

    Unfortunately, the fix isn't as clean. If you change it to case m := <-ch:, then sending m over mes will block the select, and can result in a deadlock if it's already at buffer. Probably the easiest way to fix it is to only have a single channel, rather than two. Example:

    package main
    
    import (
        "bufio"
        "fmt"
        "io"
        "os"
    )
    
    /* Function to run the groutine to run for stdin read */
    func read(r io.Reader) <-chan string {
        lines := make(chan string)
        go func() {
            defer close(lines)
            scan := bufio.NewScanner(r)
            for scan.Scan() {
                lines <- scan.Text()
            }
        }()
        return lines
    }
    
    func main() {
        mes := read(os.Stdin) //Reading from Stdin
        for anu := range mes {
            fmt.Println("Message to stdout")
            fmt.Println(anu) //Writing to Stdout
        }
    }
    

    Note that I changed your scan.Bytes() call to scan.Text(), because the comments for scan.Bytes() specifically state that the underlying array of the slice it returns is not safe against being overwritten by following Scan calls.

    Another alternative is to use a separate goroutine to translate the messages between the channels:

    package main
    
    import (
        "bufio"
        "fmt"
        "io"
        "os"
    )
    
    /* Function to run the groutine to run for stdin read */
    func read(r io.Reader) <-chan string {
        lines := make(chan string)
        go func() {
            defer close(lines)
            scan := bufio.NewScanner(r)
            for scan.Scan() {
                s := scan.Text()
                lines <- s
            }
        }()
        return lines
    }
    
    func main() {
        mes := make(chan string, 1)
        ch := read(os.Stdin) //Reading from Stdin
        go func() {
            for m := range ch {
                fmt.Println("Message to channel 2")
                mes <- m
            }
        }()
        for anu := range mes {
            fmt.Println("Message to stdout")
            fmt.Println(anu) //Writing to Stdout
        }
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥100 支付宝网页转账系统不识别账号
  • ¥15 基于单片机的靶位控制系统
  • ¥15 AT89C51控制8位八段数码管显示时钟。
  • ¥15 真我手机蓝牙传输进度消息被关闭了,怎么打开?(关键词-消息通知)
  • ¥15 下图接收小电路,谁知道原理
  • ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
  • ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
  • ¥15 手机接入宽带网线,如何释放宽带全部速度
  • ¥30 关于#r语言#的问题:如何对R语言中mfgarch包中构建的garch-midas模型进行样本内长期波动率预测和样本外长期波动率预测
  • ¥15 ETLCloud 处理json多层级问题