7445


Golangでpythonのパッケージ全てを並列実行で高速に最新にするものを作りたいのですが、どうすればいいのでしょうか?  
goルーチンを使い、書いてみましたが下記のPythonのスクリプトより遅くなってしまいます。  
Golangでマルチプロセスで実行するにはどうすればいいのでしょうか?  
下記のPythonスクリプトのようなことをGolangで実現したいと思っています。

[code]

    
    #!/usr/local/bin/python3.4
    # coding:utf-8
    
    from multiprocessing import Process
    import re
    import subprocess
    import os
    
    def u(v):
        os.system("echo 'mypassword' | sudo -S -H -p '' pip3.4 install " + v + " -U")
    
    output = subprocess.check_output(["pip3.4", "freeze"]).decode()
    output_list = re.findall(".+(?===)", output)
    output_list.extend(["pip", "setuptools"])
    print(output_list)
    
    for v in output_list:
        Process(target=u, args=(v,)).start()
    
    
[/code]

[code]

    
    package main
    
    import (
        "fmt"
        "os"
        "os/exec"
        "regexp"
        "strings"
        "log"
    )
    
    func main() {
        out, err := exec.Command("pip3.4", "freeze").Output()
        if err != nil {
            log.Fatal(err)
        }
        str_output := string(out)
        re := regexp.MustCompile(".+==")
        re_list := re.FindAllString(str_output, -1)
        for _, v := range re_list {
            c := make(chan string, 1)
            go update(v[:len(v)-2], c)
            command_output := <-c
            fmt.Println(command_output)
        }
        fmt.Println("end")
    
    }
    
    func update(package_name string, s chan string) {
        cmd := exec.Command(os.Getenv("SHELL"), "-c", "pip install "+package_name+" -U")
        cmd.Stdin = strings.NewReader("mypassword\n")
        out, err := cmd.Output()
        out_str := string(out)
        s <- out_str
        if err != nil {
            log.Fatal(err)
        }
    }
    
    
    
[/code]


CC BY-SA 3.0
2015-03-04T11:55:56.097
7441
2015-03-05T03:14:10.980
2015-03-05T03:10:08.953
440
5246
question
python go
GolangでPythonのパッケージをアップデートするプログラムについて


**条件にある Golang は使っていません** ので、以下は回答ではなく参考情報ということにしておいて下さい。

> Golangでpythonのパッケージ全てを並列実行で高速に最新にするものを作りたいのですが、…

「並列実行で高速に」という条件から、[GNU Parallel](http://www.gnu.org/software/parallel/)
を使う方法を載せておきます。

[code]

    $ pip3.4 freeze 2>/dev/null | parallel -P0 --colsep '==' "echo 'mypassword' | sudo -S -H -p '' pip3.4 install {1} -U"
    
[/code]

もっとも、コア数が少なかったり、python
パッケージの依存関係で「潰し合い」になったりする可能性もありますので、「処理速度が確実に速くなる」とは言えません。


CC BY-SA 3.0
2015-03-04T12:39:14.710
7444
2015-03-04T12:39:14.710
7441
answer


チャンネル受信時のブロックによりループの途中で`update`の終了を待機してしまうため、並列実行されていないと思います。以下のようにチャンネルの受信を別のループ内で行ってみてください。

[code]

    func main() {
        out, err := exec.Command("pip3.4", "freeze").Output()
        if err != nil {
            log.Fatal(err)
        }
        str_output := string(out)
        re := regexp.MustCompile(".+==")
        re_list := re.FindAllString(str_output, -1)
    
        c := make(chan string)
        for _, v := range re_list {
            go update(v[:len(v)-2], c)
        }
        for range re_list {
            fmt.Println(<-c)
        }
        fmt.Println("end")
    }
    
[/code]


CC BY-SA 3.0
2015-03-04T14:43:25.960
7445
2015-03-04T14:43:25.960
3639
7441
answer


まず遅い原因ですが

[code]

    command_output := <-c
    
[/code]

これはチャネルから受信待ちする命令ですので、for ループ毎で毎回プロセスの終了待ちを行っている事になります。  
つまり並列で動いていません。Println したい要件だけなら h2so5 さんのコードの様に変更すると並列で起動する様になります。

ただ、pip の仕様を知りませんがパッケージインデックス等を書いているのであれば並列で実行するのは危険な行為になりかねませんのでご注意ください。


CC BY-SA 3.0
2015-03-05T03:14:10.980
7461
2015-03-05T03:14:10.980
440
7441
answer