2017-04-25 3 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 

*/ 
} 

Möchten Sie die o/P wie oben gezeigt erreichen.Möchten Sie von os.Stdin zu os.Stdout mit den Kanälen schreiben

Wir schreiben von einem Kanal, der die gesamte stdin vom Benutzer liest und dann in die stdout schreibt. Der Kanal liest sich in Goroutine. Ein Dummy-Kanal wird gebildet (sig), so dass wir ihn unbegrenzt laufen können (nur für den Moment).

+1

Ich denke, diese Hausaufgaben? – Flimzy

+1

Sie können das von einem bufio.Scanner verwendete Slice nicht teilen - aus der Dokumentation: 'Das zugrunde liegende Array kann auf Daten zeigen, die bei einem nachfolgenden Aufruf von Scan überschrieben werden. – JimB

+0

Bitte' gofmt' verwenden. Ich weiß, dass man eine Menge Kritik darüber bekommt, ob man zu eigenwillig den WRT-Codierungsstil benutzt, aber die Art und Weise, wie der Code aussieht, macht es für Leute schwieriger, die sich an die Golaf-Standardformatierung gewöhnt haben. Der zusätzliche Platz in Anweisungen wie 'sig: = make (chan bool)' und die zusätzliche Ebene der Einrückung für Ihre'Auswahl'-Blöcke sollten nicht dort sein –

Antwort

1

Das Problem ist, dass Sie zwei Kanaloperationen in Ihrem zweiten select Fall haben. Auswahl verhindert nur, dass der äußere-Vorgang blockiert wird. Daher wird der Aufruf <-ch sofort ausgewertet und hat keinen Blockierschutz der Auswahl, so dass die gesamte Auswahlanweisung blockiert, bis etwas anderes auf diesem Kanal empfangen wird (was einen anderen Eingang erfordert, so dass read() erneut auf diesem Kanal senden kann).

Leider ist die Lösung nicht so sauber. Wenn Sie es in case m := <-ch: ändern, blockiert das Senden von m über mes die Auswahl und kann zu einem Deadlock führen, wenn es bereits im Puffer ist. Wahrscheinlich ist der einfachste Weg, es zu beheben, nur einen einzigen Kanal statt zwei zu haben. Beispiel:

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

Beachten Sie, dass ich Ihre scan.Bytes() Aufruf scan.Text() geändert, weil die Kommentare zu scan.Bytes() ausdrücklich festgelegt, dass das zugrunde liegende Array der Scheibe gibt es durch folgende Scan Anrufe nicht sicher überschrieben gegen wird.

Eine weitere Alternative ist eine separate goroutine, um die Nachrichten zwischen den Kanälen zu übersetzen:

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

Danke für die Antwort. Ich habe den Fehler bei der Verwendung von Select erkannt. – Anupam