为什么`sync.WaitGroup`无法完成?

时间:2016-12-28 06:12:51

标签: go

这是我的代码:

package main

import (
    "bytes"
    "crypto/md5"
    "encoding/hex"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "runtime"
    "sync"
)

type Data struct {
    Link string `json:"url"`
}
type Result struct {
    Code uint32
    Msg  string `json:"msg"`
    Data Data   `json:"data"`
}

const (
    URL     = "http://qiye.wxsdc.ediankai.com/api/v1/suppliers/1/staff/1/box/get"
    SIGNKEY = "i5OqMrNXVyOJ5GEMYoEtRHqN1P9ghk6I"
    DATA_ID = "2965612126"
    EQU_ID  = "1482806063"
)

func getMD5Hash(text string) string {
    hasher := md5.New()
    hasher.Write([]byte(text))
    return hex.EncodeToString(hasher.Sum(nil))
}

func getUrl(payload []byte, wg *sync.WaitGroup, result chan string) {
    req, err := http.NewRequest("POST", URL, bytes.NewBuffer(payload))
    req.Header.Set("Content-Type", "application/json")

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        panic(err)
    }
    var res Result
    json.Unmarshal(body, &res)
    log.Println(res.Data.Link)
    result <- res.Data.Link
    wg.Add(-1)
}
func main() {
    parameterStr := fmt.Sprintf("%vdata_id%vequ_id%v%v", SIGNKEY, DATA_ID, EQU_ID, SIGNKEY)
    log.Println(parameterStr)
    sign := getMD5Hash(parameterStr)
    log.Println(sign)
    var payload map[string]string = make(map[string]string)
    payload["equ_id"] = EQU_ID
    payload["data_id"] = DATA_ID
    payload["sign"] = sign

    payloadJson, err := json.Marshal(payload)
    if err != nil {
        log.Fatalln("convet paylod failed!")
    }
    log.Println(string(payloadJson))

    runtime.GOMAXPROCS(runtime.NumCPU())
    var wg sync.WaitGroup
    result := make(chan string)
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go getUrl(payloadJson, &wg, result)
    }
    wg.Wait()
    for link := range result {
        fmt.Println(link)
    }
    log.Println("Done!")
}

可是:

for link := range result {
    fmt.Println(link)
}
log.Println("Done!")

无法执行,原因是什么?

2 个答案:

答案 0 :(得分:1)

您需要关闭结果通道,以便从中读取的for循环在完成时中断。为此,您可以将最后一部分重写为:

var wg sync.WaitGroup
result := make(chan string)
go func() {
    for link := range result {
        fmt.Println(link)
    }
}()
for i := 0; i < 10; i++ {
    wg.Add(1)
    go getUrl(payloadJson, &wg, result)
}
wg.Wait()
close(result)

答案 1 :(得分:0)

你的for循环永不停止。当所有getUrl完成后,它会继续等待result。试试这个:

wg.Wait()

close(result)

for link := range result {
    fmt.Println(link)
}
log.Println("Done!")

如果要打印结果,可以这样做:

package main

import (
    "bytes"
    "crypto/md5"
    "encoding/hex"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "runtime"
    "sync"
)

type Data struct {
    Link string `json:"url"`
}
type Result struct {
    Code uint32
    Msg  string `json:"msg"`
    Data Data   `json:"data"`
}

const (
    URL     = "http://qiye.wxsdc.ediankai.com/api/v1/suppliers/1/staff/1/box/get"
    SIGNKEY = "i5OqMrNXVyOJ5GEMYoEtRHqN1P9ghk6I"
    DATA_ID = "2965612126"
    EQU_ID  = "1482806063"
)

func getMD5Hash(text string) string {
    hasher := md5.New()
    hasher.Write([]byte(text))
    return hex.EncodeToString(hasher.Sum(nil))
}

func getUrl(payload []byte, wg *sync.WaitGroup, result chan string) {
    defer func(){
wg.Done()
}();

    req, err := http.NewRequest("POST", URL, bytes.NewBuffer(payload))
    req.Header.Set("Content-Type", "application/json")

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
return
    }
    defer resp.Body.Close()

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return
    }
    var res Result
    json.Unmarshal(body, &res)
    log.Println(res.Data.Link)
    result <- res.Data.Link
}

func monitor(wg *sync.WaitGroup, cs chan string) {
    wg.Wait()
    close(cs)
}
func printResult(result <-chan string, done chan<- bool) {
    for i := range result {
        fmt.Println(i)
    }

    done <- true
}

func main() {
    parameterStr := fmt.Sprintf("%vdata_id%vequ_id%v%v", SIGNKEY, DATA_ID, EQU_ID, SIGNKEY)
    log.Println(parameterStr)
    sign := getMD5Hash(parameterStr)
    log.Println(sign)
    var payload map[string]string = make(map[string]string)
    payload["equ_id"] = EQU_ID
    payload["data_id"] = DATA_ID
    payload["sign"] = sign

    payloadJson, err := json.Marshal(payload)
    if err != nil {
        log.Fatalln("convet paylod failed!")
    }
    log.Println(string(payloadJson))

    runtime.GOMAXPROCS(runtime.NumCPU())
    var wg sync.WaitGroup
    result := make(chan string)
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go getUrl(payloadJson, &wg, result)
    }

    go monitor(&wg, result)

    done := make(chan bool, 1)
    go printResult(result, done)
    <-done
    log.Println("Done!")
}