写点什么

Go 语言开发小技巧 & 易错点 100 例(四)

作者:海风极客
  • 2023-04-14
    北京
  • 本文字数:2471 字

    阅读完需:约 8 分钟

往期回顾:



本期看点(技巧类用【技】表示,易错点用【易】表示)


(1)goroutine 控制并发数量的方式【技】


(2)Go 发起 HTTP 请求【技】


(3)包循环依赖导致的异常【易】


正文如下:

1 goroutine 控制并发数量的方式【技】

首先我们思考一个问题,为什么要控制 goroutine 的数量呢?


虽然 goroutine 的创建成本很低,而且占用的内存也很少,但是一旦数量没有控制,导致短时间内大量的 goroutine 同时执行也会造成内存崩溃、CPU 占用率过高等问题,因此我们在生产级的项目中一定要注意控制好 goroutine 的数量,以免发生生产事故。


那么,我们都有哪些方式来控制 goroutine 的数量呢?


  • sync.WaitGroup

  • channel

  • sync.WaitGroup+channel

  • semaphore


(1)最简单的方式


func main() {   group := sync.WaitGroup{}   group.Add(3)
for i := 0; i < 3; i++ { go func() { fmt.Println("hello...") group.Done() }() }
group.Wait()}
复制代码


这种方式非常的简单,但是弊端就是不容易灵活扩展


(2)sync.WaitGroup+channel 方式


type Pool struct {   queue chan int   wg    *sync.WaitGroup}
func New(size int) *Pool { if size <= 0 { size = 1 } return &Pool{ queue: make(chan int, size), wg: &sync.WaitGroup{}, }}
func (p *Pool) Add(delta int) { for i := 0; i < delta; i++ { p.queue <- 1 } for i := 0; i > delta; i-- { <-p.queue } p.wg.Add(delta)}
func (p *Pool) Done() { <-p.queue p.wg.Done()}
func (p *Pool) Wait() { p.wg.Wait()}
复制代码


测试:


func main() {   pool := pool.New(10)   for i := 0; i < 100; i++ {      pool.Add(1)      go func() {         time.Sleep(time.Second)         fmt.Printf("%d hello...\n", i)         pool.Done()      }()   }   pool.Wait()}
复制代码

2 Go 发起 HTTP 请求【技】

服务端:


type Student struct {   Name string   Age  int}
func HttpServe() { /** URL:http://localhost:8080 Method:Get */ http.HandleFunc("/get", func(w http.ResponseWriter, r *http.Request) { str := r.URL.Query().Get("str") fmt.Println("Get Method Str is " + str) w.Write([]byte("Hello Http Get!")) })
/** URL:http://localhost:8080 Method:Get Param:str */ http.HandleFunc("/get/form", func(w http.ResponseWriter, r *http.Request) { name := r.URL.Query().Get("name") age := r.URL.Query().Get("age") ageStr, err := strconv.Atoi(age) if err != nil { fmt.Println("err...") } stu := Student{Name: name, Age: ageStr} fmt.Println("Get Method Str is ", stu) w.Write([]byte("Hello Http Get Form!")) })
/** URL:http://localhost:8080 Method:Get Param:str */ http.HandleFunc("/get/json", func(w http.ResponseWriter, r *http.Request) { fmt.Println("req method : ", r.Method) body, err := io.ReadAll(r.Body) if err != nil { fmt.Printf("获取请求体错误 , %v\n", err) return } fmt.Println("请求体 :", string(body)) var stu Student if err = json.Unmarshal(body, &stu); err != nil { fmt.Printf("反序列化失败 , %v\n", err) return } fmt.Printf("反序列化成功,JSON解析结果 %+v", stu) w.Write([]byte("Hello Http Get Form!")) }) err := http.ListenAndServe(":8080", nil) if err != nil { fmt.Println(err) }}
复制代码


Go 发送 Http 请求:


func HttpGet() {   resp, err := http.Get("http://localhost:8080/get?str=ymx") // url   if err != nil {      fmt.Printf("get请求失败 error: %+v", err)      return   }   defer resp.Body.Close()   body, err := io.ReadAll(resp.Body)   if err != nil {      fmt.Printf("读取Body失败 error: %+v", err)      return   }   fmt.Println(string(body))}
func HttpPost() { resp, err := http.PostForm("http://localhost:8080/form", url.Values{ "name": {"jack"}, }) if err != nil { fmt.Printf("postForm请求失败 error: %+v", err) return } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { fmt.Printf("读取Body失败 error: %+v", err) return } fmt.Println(string(body))
}
复制代码

3 包循环依赖导致的异常【易】

循环依赖是一个在代码层面很常见的概念了,简单来说就是 A 依赖 B,B 依赖 A,从而导致的先有蛋还是先有鸡的问题,下面来一个示例:



package_a 代码:


package package_a
import ( "encoding/json" "other/article5/pack/package_b")
func MakeStudent(stu package_b.Student) string { bytes, _ := json.Marshal(stu) return string(bytes)}
复制代码


package_b 代码:


package package_b
import "other/article5/pack/package_a"
type Student struct { Id int64 Name string}
func (stu *Student) GetStuJSON() string { return package_a.MakeStudent(*stu)}
复制代码


测试方法:


package main
import ( "fmt" "other/article5/pack/package_b")
func main() { student := package_b.Student{ Name: "zs", }
str:= student.GetStuJSON()
fmt.Println(str)}
复制代码


执行结果:



如何避免循环依赖呢?


说实话没有什么特别好的办法,就是在平时写代码前先做好设计,设计好每一层的依赖关系,尽量不要产生额外的循环依赖即可。

发布于: 刚刚阅读数: 3
用户头像

海风极客

关注

做兴趣使然的Hero 2021-01-14 加入

Just do it.

评论

发布
暂无评论
Go语言开发小技巧&易错点100例(四)_三周年连更_海风极客_InfoQ写作社区