2017-04-25 4 views
-2
/* 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を達成したいですか?チャンネルを使用してos.Stdinからos.Stdoutに書きたい

ユーザーからのすべてのstdinを読み込んでstdoutに書き込む1つのチャネルから書き込みを行っています。 goroutineでチャンネルの読み込みが行われています。ダミーチャネルが形成され(sig)、私たちは無期限に実行することができます(今のところ)。

+1

私は、これは宿題ですね? – Flimzy

+1

bufio.Scannerで使用されているスライスを共有することはできません。ドキュメントから: '基本配列は、後続の呼び出しで上書きされるデータを指すことがあります。 ' – JimB

+0

' gofmt'を使用してください。私は、行き過ぎたWRTコーディングスタイルのためにかなりの批判を受けることを知っていますが、あなたのコードの見た目は、golang標準フォーマットに慣れたpplを読むのが難しくなります。 'sig:= make(chan bool)'や 'select-case'ブロックの余分なインデントレベルは、そこには存在しないはずです。 –

答えて

1

問題は、2番目のselectケースに2つのチャネル操作があることです。選択すると、外側の操作がブロックされないようにします。したがって、<-chコールはすぐに評価され、selectのブロック保護がないため、select文全体がそのチャネルで受信されるまでブロックされます(別の入力が必要になるため、read()はそのチャネルで再度送信できます)。

残念ながら、この修正はきれいではありません。 case m := <-ch:に変更すると、mmesに送信すると選択がブロックされ、すでにバッファに入っているとデッドロックが発生する可能性があります。おそらくそれを修正する最も簡単な方法は、2つではなく1つのチャネルを持つことだけです。例:scan.Bytes()のコメントは、特にそれが返すスライスの根本的な配列がスキャンの呼び出しを次によって上書きされるに対して安全ではないと述べているので、私は、scan.Text()にごscan.Bytes()コールを変更

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

注意。

別の方法としては、チャンネル間のメッセージを翻訳するために別のゴルーチンを使用することです:

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

返事をありがとう。私はselectの使い方に間違いを感じました。 – Anupam

関連する問題