簡體   English   中英

為什么`sync.WaitGroup`無法完成?

[英]why `sync.WaitGroup` can't finish?

這是我的代碼:

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!")

無法執行,是什么原因?

您需要關閉結果通道,以便從其讀取的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)

您的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!")
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM