如何在Golang中并发地通过STDIN/STDOUT连接多个程序进行读写?

huangapple go评论111阅读模式
英文:

How to wire up multiple programs reading/writing via STDIN/STDOUT in Golang concurrently?

问题

在高层次上,我想要实现以下内容。每个方框都是一个从标准输入读取并写入标准输出的运行程序。我想编写一个 Go 语言程序来设置并运行这些程序,以便所有的生产和消费都是并行进行的。我考虑使用 io.Pipe、通道和 os.Exec 等方法。

  1. +-----------+
  2. | PROG-1 +-----------------------+
  3. +---------> | | v
  4. | +-----------+
  5. | +-------+
  6. +-----------+ | DIFF +----->
  7. | GENERATOR | | |
  8. +-----------+ +---+---+
  9. | ^
  10. | |
  11. | +-----------+ |
  12. | | | |
  13. +---------> | PROG-2 +-----------------------+
  14. +-----------+

这是一个尝试,但似乎不太可靠,而且 "DIFF" 部分没有实现。

  1. package main
  2. import (
  3. "io"
  4. "os"
  5. "os/exec"
  6. )
  7. const UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  8. const LOWER = "abcdefghijklmnopqrstuvwxyz"
  9. func runProg(r io.Reader, cmd *exec.Cmd) {
  10. cmd.Stdin = r
  11. cmd.Stdout = os.Stdout // 我希望这部分输出传递给一个名为 "diff" 的第三个程序调用。
  12. cmd.Run()
  13. }
  14. func runIt(r io.Reader, prog1 *exec.Cmd, prog2 *exec.Cmd) {
  15. r1, w1 := io.Pipe()
  16. r2, w2 := io.Pipe()
  17. go runProg(r1, prog1)
  18. go runProg(r2, prog2)
  19. go func() {
  20. defer w1.Close()
  21. defer w2.Close()
  22. mw := io.MultiWriter(w1, w2)
  23. io.Copy(mw, r)
  24. }()
  25. }
  26. func main() {
  27. generator := exec.Command("ls", "-l")
  28. r, w := io.Pipe()
  29. generator.Stdout = w
  30. prog1 := exec.Command("tr", LOWER, UPPER)
  31. prog2 := exec.Command("tr", UPPER, LOWER)
  32. runIt(r, prog1, prog2)
  33. generator.Run()
  34. }
英文:

At a high level I would like to accomplish the following. Each box is a running program reading from STDIN and writing to STDOUT. I want to write a golang program which sets this up and runs it so that all production/consumption is happening in parallel. I am thinking of using io.Pipe, channels, and os.Exec etc.

  1. +-----------+
  2. | PROG-1 +-----------------------+
  3. +---------> | | v
  4. | +-----------+
  5. | +-------+
  6. +-----------+ | DIFF +----->
  7. | GENERATOR | | |
  8. +-----------+ +---+---+
  9. | ^
  10. | |
  11. | +-----------+ |
  12. | | | |
  13. +---------> | PROG-2 +-----------------------+
  14. +-----------+

Here's an attempt but it doesn't seem to be working reliably and also the "DIFF" part is not implemented.

  1. package main
  2. import (
  3. "io"
  4. "os"
  5. "os/exec"
  6. )
  7. const UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  8. const LOWER = "abcdefghijklmnopqrstuvwxyz"
  9. func runProg(r io.Reader, cmd *exec.Cmd) {
  10. cmd.Stdin = r
  11. cmd.Stdout = os.Stdout // I want this to go to a third prog call "diff".
  12. cmd.Run()
  13. }
  14. func runIt(r io.Reader, prog1 *exec.Cmd, prog2 *exec.Cmd) {
  15. r1, w1 := io.Pipe()
  16. r2, w2 := io.Pipe()
  17. go runProg(r1, prog1)
  18. go runProg(r2, prog2)
  19. go func() {
  20. defer w1.Close()
  21. defer w2.Close()
  22. mw := io.MultiWriter(w1, w2)
  23. io.Copy(mw, r)
  24. }()
  25. }
  26. func main() {
  27. generator := exec.Command("ls", "-l")
  28. r, w := io.Pipe()
  29. generator.Stdout = w
  30. prog1 := exec.Command("tr", LOWER, UPPER)
  31. prog2 := exec.Command("tr", UPPER, LOWER)
  32. runIt(r, prog1, prog2)
  33. generator.Run()
  34. }

答案1

得分: 3

这里有几个问题。创建所有这些管道会增加工作量和复杂性。此外,使用Cmd.Start()和Cmd.Wait()可以内置并发运行命令。

  1. package main
  2. import (
  3. "fmt"
  4. "io"
  5. "os"
  6. "os/exec"
  7. )
  8. const UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  9. const LOWER = "abcdefghijklmnopqrstuvwxyz"
  10. func runProg(cmd *exec.Cmd) (w io.WriteCloser, err error) {
  11. w, err = cmd.StdinPipe()
  12. if err != nil {
  13. fmt.Println(err)
  14. }
  15. cmd.Stdout = os.Stdout
  16. err = cmd.Start()
  17. return w, err
  18. }
  19. func runIt(r io.Reader, prog1 *exec.Cmd, prog2 *exec.Cmd) {
  20. w1, err := runProg(prog1)
  21. if err != nil {
  22. fmt.Println(err)
  23. }
  24. w2, err := runProg(prog2)
  25. if err != nil {
  26. fmt.Println(err)
  27. }
  28. go func() {
  29. defer w1.Close()
  30. defer w2.Close()
  31. mw := io.MultiWriter(w1, w2)
  32. io.Copy(mw, r)
  33. }()
  34. }
  35. func main() {
  36. generator := exec.Command("ls", "-l")
  37. r, err := generator.StdoutPipe()
  38. if err != nil {
  39. fmt.Println(err)
  40. }
  41. prog1 := exec.Command("tr", LOWER, UPPER)
  42. prog2 := exec.Command("tr", UPPER, LOWER)
  43. runIt(r, prog1, prog2)
  44. generator.Run()
  45. err = prog1.Wait()
  46. err1 := prog2.Wait()
  47. if err != nil || err1 != nil {
  48. fmt.Println(err, err1)
  49. }
  50. }
英文:

There are a couple things here. You're adding work and complexity in creating all those pipes. Also, running the command concurrently is built-in using Cmd.Start() and Cmd.Wait().

  1. package main
  2. import (
  3. "fmt"
  4. "io"
  5. "os"
  6. "os/exec"
  7. )
  8. const UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  9. const LOWER = "abcdefghijklmnopqrstuvwxyz"
  10. func runProg(cmd *exec.Cmd) (w io.WriteCloser, err error) {
  11. w, err := cmd.StdinPipe()
  12. if err != nil {
  13. fmt.Println(err)
  14. }
  15. cmd.Stdout = os.Stdout
  16. err = cmd.Start()
  17. }
  18. func runIt(r io.Reader, prog1 *exec.Cmd, prog2 *exec.Cmd) {
  19. w1, err := runProg(prog1)
  20. if err != nil {
  21. fmt.Println(err)
  22. }
  23. w2, err := runProg(prog2)
  24. if err != nil {
  25. fmt.Println(err)
  26. }
  27. go func() {
  28. defer w1.Close()
  29. defer w2.Close()
  30. mw := io.MultiWriter(w1, w2)
  31. io.Copy(mw, r)
  32. }()
  33. }
  34. func main() {
  35. generator := exec.Command("ls", "-l")
  36. r, err := generator.StdoutPipe()
  37. if err != nil {
  38. fmt.Println(err)
  39. }
  40. prog1 := exec.Command("tr", LOWER, UPPER)
  41. prog2 := exec.Command("tr", UPPER, LOWER)
  42. runIt(r, prog1, prog2)
  43. generator.Run()
  44. err = prog1.Wait()
  45. err1 := prog2.Wait()
  46. if err != nil || err1 != nil {
  47. fmt.Println(err, err1)
  48. }
  49. }

huangapple
  • 本文由 发表于 2015年9月13日 08:23:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/32545103.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定