go - 想要使用 channel 从 os.Stdin 写入 os.Stdout

标签 go channel

/* 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

*/
}

想要达到上面显示的O/P。

我们正在从一个 channel 写入,该 channel 从用户读取所有标准输入,然后写入标准输出。 channel 读取发生在 goroutine 中。形成了一个虚拟 channel (sig),以便我们可以无限期地运行它(只是现在)。

最佳答案

问题是您在第二个 select 中有两个 channel 操作案件。 Select 仅防止外部 操作被阻塞。因此 <-ch call 被立即评估,并且没有 select 的阻塞保护,因此整个 select 语句阻塞,直到在该 channel 上收到其他内容(这需要另一个输入,以便 read() 可以在该 channel 上再次发送)。

不幸的是,修复不是那么干净。如果将其更改为 case m := <-ch: , 然后发送 mmes将阻止选择,如果它已经在缓冲区,则可能导致死锁。修复它的最简单方法可能是只有一个 channel ,而不是两个。示例:

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
    }
}

请注意,我更改了您的 scan.Bytes()调用 scan.Text() , 因为 scan.Bytes() 的评论特别说明它返回的 slice 的底层数组对于被后续 Scan 调用覆盖是不安全的。

另一种选择是使用单独的 goroutine 来翻译 channel 之间的消息:

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
    }
}

关于go - 想要使用 channel 从 os.Stdin 写入 os.Stdout,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43610646/

相关文章:

go - Couchbase gocb 批量操作提供部分为空的结果

go - 运行时错误 :Invalid memory Address or nil pointer dereference-golang

google-app-engine - Bitbucket Pipeline Deploy 问题到 Google App Engine

asterisk - Asterisk 中的 channel 名称

从不完整的字符串解析 golang 时间对象

google-analytics - 谷歌分析 : what is the difference between "Referral" default system channel"and "referral" medium?

ffmpeg - 在保留 Alpha channel 的同时压缩视频

multithreading - Golang 中的 channel 和 mutex 有什么区别?

java - 了解 netty channel 缓冲区和水印

go - 在 Golang 中使用 Redis 配置 gin-gonic session