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

来源:1-14 Go 并发编程最佳实践

qq_Tto_0

2021-07-06 07:56:55

问题描述:

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回答

Xargin

2021-07-06

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


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

0
hq_Tto_0
hp>明白了,谢谢曹大,我又改了一版

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)
}
}


h021-07-07
共1条回复

Go高级工程师实战营

慕课网与 GoCN 社区官方联手打造,定义行业Go高级人才培养标准,4个月,快速晋升为P6+/D7级高级人才。

458 学习 · 266 问题

查看课程