我想让它根据线程数运行并行。但结果并不像我预期的那样。我不知道如何使它高效快速。
我最终得到了这段代码。
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
答案 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()