切片的并行性

时间:2017-06-17 06:33:35

标签: multithreading go parallel-processing slice

我想让它根据线程数运行并行。但结果并不像我预期的那样。我不知道如何使它高效快速。

我最终得到了这段代码。

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
}

任何帮助将不胜感激。谢谢。

更新 这是我目前的结果:

$ 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

2 个答案:

答案 0 :(得分:1)

您没有正确使用waitgroup。 defer for循环中的main永远不会被调用,因为main永远不会返回,因此wg.Wait()调用永远不会被解除阻塞。

defer个电话放入发送消息的goroutine中:

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

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

同时关闭jobs频道:

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

答案 1 :(得分:0)

你应该为每个新工作创建新的goroutine,而不是根据新增的工作

在这里,你要创建一个goroutine日志,只将一个单词推送到频道。这对于这么简单的操作来说太过分了。

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

但是获取网址的工作更重,但为此只启动1个goroutine。

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

正如@abhink提到你没有正确使用WaitGroup。在创建每个goroutine之前执行wg.Add(1)并在每个goroutine结束时执行wg.Done()。当然wg.Wait()等待所有正在运行的goroutines完成。例如:

var wg sync.WaitGroup

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

//...

wg.Wait()
相关问题