2016-10-25 1 views
2

Я довольно новыми для Golang в целом, и я пытаюсь выполнить bash command with its arguments n times, то хранить Output в переменной и Print его.Go - выполнить Bash Command п раз, используя goroutines и магазин и распечатать свой результат

Я могу сделать это только один раз, или просто используя loops как следующее:

package main 

import (
    "fmt" 
    "os/exec" 
    "os" 
    "sync" 
) 


func main() { 

    //Default Output 
    var (
     cmdOut []byte 
     err error 
    ) 

    //Bash Command 
    cmd := "./myCmd" 
    //Arguments to get passed to the command 
    args := []string{"arg1", "arg2", "arg3"} 

    //Execute the Command 
    if cmdOut, err = exec.Command(cmd, args...).Output(); err != nil { 
     fmt.Fprintln(os.Stderr, "There was an error running "+cmd+" "+args[0]+args[1]+args[2], err) 
     os.Exit(1) 
    } 
    //Store it 
    sha := string(cmdOut) 
    //Print it 
    fmt.Println(sha) 
} 

Это прекрасно работает, я могу читать output легко.

Теперь, я хотел бы повторить эту же операцию для n раз, используя goroutines.

Я пробовал следовать тому же подходу парня, который ответил How would you define a pool of goroutines to be executed at once in Golang?, но я не могу заставить его работать.

Вот что я пытался до сих пор:

package main 

import (
    "fmt" 
    "os/exec" 
    "sync" 
) 


func main() { 

    //Bash Command 
    cmd := "./myCmd" 
    //Arguments to get passed to the command 
    args := []string{"arg1", "arg2", "arg3"} 

    //Common Channel for the goroutines 
    tasks := make(chan *exec.Cmd, 64) 

    //Spawning 4 goroutines 
    var wg sync.WaitGroup 
    for i := 0; i < 4; i++ { 
     wg.Add(1) 
     go func() { 
      for cmd := range tasks { 
       cmd.Run() 
      } 
      wg.Done() 
     }() 
    } 

    //Generate Tasks 
    for i := 0; i < 10; i++ { 
     tasks <- exec.Command(cmd, args...) 
     //Here I should somehow print the result of the latter command 
    } 
    close(tasks) 

    // wait for the workers to finish 
    wg.Wait() 

    fmt.Println("Done") 

} 

Но я на самом деле не узнать, как хранить i-result казненного команды и распечатать его.

Как я могу это достичь?

Заранее благодарим за любые разъяснения по вопросу, просто оставляйте комментарий.

ответ

2

поэтому следующие исправления вашей проблемы

  • можно назвать Cmd.Output(), чтобы получить вывод команды. , иначе вы могли бы подключить трубу Cmd.StdOutPipe к байту. Буффер для примера и прочитать из этого.

  • Ваша логика goroutine была неправильной. он будет выполняться только в 4 раза, а затем waitgroup будет Done(), и main выйдет. Вы правильно закрываете канал из основного, чтобы сигнализировать рабочим о выходе из цикла диапазона. wg.Done следует вызвать после этого, поэтому я отложил его.

  • при выполнении анонимных функций с помощью команды go старайтесь не захватывать что-либо из родительской области. это может привести к катастрофе. вместо этого выясните, какие параметры вы хотите, и передайте их функции.

`

package main 

import (
    "fmt" 
    "os/exec" 
    "sync" 
) 
func main() { 
    cmd := "./foo.sh" 
    //Arguments to get passed to the command 
    args := []string{"bar", "baz"} 

    //Common Channel for the goroutines 
    tasks := make(chan *exec.Cmd, 64) 

    //Spawning 4 goroutines 
    var wg sync.WaitGroup 
    for i := 0; i < 4; i++ { 
      wg.Add(1) 
      go func(num int, w *sync.WaitGroup) { 
        defer w.Done() 
        var (
          out []byte 
          err error 
        ) 
        for cmd := range tasks { // this will exit the loop when the channel closes 
          out, err = cmd.Output() 
          if err != nil { 
            fmt.Printf("can't get stdout:", err) 
          } 
          fmt.Printf("goroutine %d command output:%s", num, string(out)) 
        } 
      }(i, &wg) 
    } 
    //Generate Tasks 
    for i := 0; i < 10; i++ { 
      tasks <- exec.Command(cmd, args...) 
    } 
    close(tasks) 

    // wait for the workers to finish 
    wg.Wait() 

    fmt.Println("Done") 

} 

`

+0

Всего, что я искал, спасибо. Еще один маленький вопрос. Считаете ли вы, что это самый экономичный способ выполнения «параллельных» операций с использованием 'Go'? Я должен сделать это как '1.000.000' разных' a [0] 'аргументов и сохранить результат в' файле' или в 'db' (например, MongoDB). – AndreaM16

+0

Это действительно зависит. хостинг goroutines - это фантастический способ раздать рабочие места десяткам тысяч рабочих. я боюсь, что в вашей проблеме вы, вероятно, попадете в стену, вероятно, с вашим драйвером db. многие соединители базы данных golang хорошо масштабируются вместе с большим количеством рабочих (я не знаю о MongoDB, но в cassandra, которые я использовал, обязательно включите их в сеанс базы данных). на другом конце выполняется 1 мил процессов из вашего скрипта. снова ... какова средняя продолжительность выполнения команды?можете ли вы запускать ops, объединив несколько тысяч аргументов в одном вызове команды? – ramrunner

+0

Для выполнения этого требуется «42 секунды» и распечатать его «100 000» раз. Это довольно медленный скрипт шифрования Ocaml. Я должен каждый раз передавать разные «шестерки шести шестерен» и сохранять результат. Ну, с «NodeJS» я действительно изо всех сил пытался получить такую ​​производительность. Теперь, как вы сказали, мне нужно проверить, является ли сохранение результатов на «MongoDB» хорошей идеей или нет. К несчастью, нет, я не могу передать его больше, чем 'a [0]' за время. Он принимает '-s',' Hex Key' и 'A 24 Hex Chars PlainText'. Поэтому я должен выполнить его для каждого другого ключа в диапазоне '000000' -' FFFFFF'. – AndreaM16