并发编程最佳实践作业疑问

并发编程最佳实践作业疑问

问题描述:

1、lock := make(chan content) 需要加buffer吗?试了一下不加程序也不会挂掉,加了是不是可以防止channel阻塞?

2、go fetch(name, lock) 协程里面执行http请求,如果http请求超时,会不会导致 c := <-lock 代码处阻塞?

​3、下图代码还有没有其它问题?

相关代码:

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
)

type content struct {
    name string
    url  string
    body []byte
}

func main() {
    urls := []string{
        "baidu.com",
        "bing.com",
    }

    lock := make(chan content)
    for _, name := range urls {
        go fetch(name, lock)
    }
    c := <-lock
    writeToFile(c.name, c.url, c.body)
}

func fetch(name string, lock chan content) {
    url := fmt.Sprintf("https://%s", name)
    resp, err := http.Get(url)
    if err != nil {
        panic("request failed")
    }
    defer resp.Body.Close()

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        panic("Failed to read buffer data")
    }

    content := content{
        name: name,
        url:  url,
        body: body,
    }
    lock <- content
}

func writeToFile(name, url string, body []byte) {
    if err := ioutil.WriteFile("./"+name+".html", body, 0644); err != nil {
        panic("Failed to write to file")
    }
}

正在回答

登陆购买课程后可参与讨论,去登陆

1回答

按生产标准来写的话,你这里超时就会导致 goroutine 泄露~


生产环境向外发请求一定要加超时,不要直接用 http.Get 这种 API

  • qq_Tto_0 提问者 #1

    明白了,谢谢曹大,我又改了一版

    package main

    import (
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "time"
    )

    type Handle struct {
    client *http.Client
    lock chan content
    }

    func NewClient() *Handle {
    client := &http.Client{
    Timeout: 30 * time.Second,
    }
    lock := make(chan content)
    return &Handle{client, lock}
    }

    type content struct {
    name string
    url string
    body []byte
    }

    func main() {
    n := NewClient()
    urls := []string{
    "baidu.com",
    "bing.com",
    }

    for _, name := range urls {
    go n.fetch(name)
    }
    c := <-n.lock;
    n.writeToFile(c.name, c.url, c.body)
    }

    func (n *Handle) fetch(name string) {
    url := fmt.Sprintf("https://%s", name)
    req, _ := http.NewRequest(http.MethodGet, url, nil)
    resp, err := n.client.Do(req)
    if err != nil {
    fmt.Printf("request error, err:%s", err)
    return
    }
    defer resp.Body.Close()
    if resp.StatusCode != http.StatusOK {
    fmt.Printf("response err status code: %d,url: %s\n", resp.StatusCode, req.URL)
    return
    }

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
    log.Fatalf("Failed to read buffer data, err:%s", err)
    }

    content := content{
    name: name,
    url: url,
    body: body,
    }
    n.lock <- content
    }

    func (n *Handle) writeToFile(name, url string, body []byte) {
    if err := ioutil.WriteFile("./"+name+".html", body, 0644); err != nil {
    fmt.Printf("Failed to write to file, err:%s\n", err)
    }
    }


    2021-07-07 19:58:48
问题已解决,确定采纳
还有疑问,暂不采纳

恭喜解决一个难题,获得1积分~

来为老师/同学的回答评分吧

0 星
请稍等 ...
意见反馈 帮助中心 APP下载
官方微信

在线咨询

领取优惠

免费试听

领取大纲

扫描二维码,添加
你的专属老师