2017-06-17 7 views
-3

スレッドの数に基づいて並列実行させたいと考えています。しかし、結果は私が期待した通りではありませんでした。私はそれを効率的かつ高速にする方法を知らない。スライスからの平行度

私はこのコードで終わった。

package main 

import (
    "fmt" 
    "io/ioutil" 
    "net/http" 
    "os" 
    "runtime" 
    "strconv" 
    "strings" 
    "sync" 
    "time" 
) 

func main() { 
    start := time.Now() 
    target := os.Args[1] 
    thread, _ := strconv.Atoi(os.Args[3]) 
    file, err := ioutil.ReadFile(os.Args[2]) 
    if err != nil { 
     fmt.Println("Error: Please double check if the file " + os.Args[2] + " is exist!") 
     os.Exit(0) 
    } 
    wordlist := strings.Split(string(file), "\n") 

    var wg sync.WaitGroup 
    runtime.GOMAXPROCS(runtime.NumCPU()) 
    jobs := make(chan string) 
    for i := 0; i < thread; i++ { 
     wg.Add(1) 
     defer wg.Done() 
     for _, word := range wordlist { 
      go func(word string) { 
       jobs <- word 
      }(word) 
     } 
    } 

    go func() { 
     for job := range jobs { 
      code := visit(target + job) 
      fmt.Println(target + job + " - " + strconv.Itoa(code)) 
     } 
    }() 
    wg.Wait() 

    elapsed := time.Since(start) 
    fmt.Printf("Timer: %s\n", elapsed) 
} 

func visit(url string) int { 
    data, err := http.Get(url) 
    if err != nil { 
     panic(err) 
    } 
    return data.StatusCode 
} 

助けてください。ありがとうございました。あなたは正しくwaitgroupを使用していない

$ go run test.go http://localhost/ word.txt 2 
http://localhost/1 - 404 
http://localhost/1 - 404 
http://localhost/7 - 404 
http://localhost/8 - 404 
http://localhost/9 - 404 
http://localhost/0 - 404 
http://localhost/ - 200 
http://localhost/3 - 404 
http://localhost/2 - 404 
http://localhost/4 - 404 
http://localhost/6 - 404 
http://localhost/2 - 404 
http://localhost/3 - 404 
http://localhost/4 - 404 
http://localhost/5 - 404 
http://localhost/9 - 404 
http://localhost/7 - 404 
http://localhost/8 - 404 
http://localhost/0 - 404 
http://localhost/5 - 404 
http://localhost/ - 200 
http://localhost/6 - 404 
+1

あなたの問題を説明するために、[最小限の完全な検証可能な例](https://stackoverflow.com/help/how-to-ask)を参照してください。 – abhink

+0

ブロックされたチャネル 'jobs:= make(chan string)'の代わりに、バッファーに入れられたチャネル 'jobs:= make(chan string、100)'を使用することができます。また、@ abhinkで述べたようにwaitgroupの 'defer'も更新してください。 – jeevatkm

+0

@abhink oh ok、申し訳ありません。私は私の質問を更新します。 – Alkha

答えて

1

更新 は、これは私の現在の結果です。 mainが返されず、結果としてwg.Wait()コールが決してブロック解除されないので、のmainのforループは呼び出されません。

は、メッセージを送信ゴルーチンでdefer呼び出しを入れて:

// ... 
wg.Wait() 
close(jobs) 
// ... 
+0

こんにちは@abhink、私は自分のコードに入れようとしましたが、別の問題があります。 xスレッドの後にプロセスが停止しました。 $はtest.goはhttpを実行しに行く:// localhost /をword.txt 10 ます。http:// localhost /を2から404 ます。http:// localhost /を7から404 ます。http:// localhost /を3から404 のhttp :// localhost/4 - 404 http:// localhost/5 - 404 http:// localhost/6 - 404 http:// localhost/- 200 http:// localhost/8 - 404 http: // localhost/9 - 404 タイマー:3.734229ms – Alkha

+0

彼は 'jobs'チャンネルを閉じてみます。 – abhink

0

あなたは新しいジョブごとではなく、新しいジョブごとに新しいゴルーチンを作成する必要があります

を追加しました:

// ... 
for i := 0; i < thread; i++ { 
    wg.Add(1) 

    for _, word := range wordlist { 
     go func(word string) { 
      defer wg.Done() 
      jobs <- word 
     }(word) 
    } 
} 
// ... 

またjobsチャネルがクローズ

ここでは、1単語だけをチャンネルにプッシュするためのゴルーチンのログを作成しています。これは、このような簡単な操作のための過度の操作です。

for _, word := range wordlist { 
     go func(word string) { 
      jobs <- word 
     }(word) 
    } 

しかし、URLを取得するジョブはより重くなりますが、このためには1つのゴルーチンしか開始しません。

go func() { 
    for job := range jobs { 
     code := visit(target + job) 
     fmt.Println(target + job + " - " + strconv.Itoa(code)) 
    } 
}() 

@abhinkは、WaitGroupを正しく使用していないと述べています。それぞれのゴルーチンを作成する前にwg.Add(1)を実行し、各ゴルーチンの最後にwg.Done()を実行してください。もちろん、wg.Wait()は実行中のすべてのゴルーチンが終了するまで待つ必要があります。例:

var wg sync.WaitGroup 

wg.Add(1) 
go func(param){ 
    defer wg.Done() 
    //... 
}(url) 

//... 

wg.Wait() 
関連する問題