Skip to content

Commit

Permalink
feat(concurrency): add concurrency optimization
Browse files Browse the repository at this point in the history
  • Loading branch information
shgopher committed Feb 27, 2024
1 parent c929061 commit 8ea835e
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 6 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ hey~,我是科科,目前就职于国内一家互联网公司,你们可以
- [channel](./并发/channel)
- [context](./并发/context)
- [atomic](./并发/atomic)
- [并发优化](./并发/并发优化)
## runtime
- [三色 gc 算法](./runtime/三色gc算法)
- [G:M:P](./runtime/gmp)
Expand Down
1 change: 1 addition & 0 deletions 基础/slice/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# 切片

导读:

- 切片的基本操作
- 切片和数组的基本概念
- 切片数组的底层数据结构
Expand Down
1 change: 1 addition & 0 deletions 并发/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@
- [channel](./channel)
- [atomic](./atomic)
- [context](./context)
- [并发优化](./并发优化)
4 changes: 2 additions & 2 deletions 并发/channel/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ for value := range ch{
fmt.Println(value)
}
```
值得注意的是,一个 channel 如果没有被关闭,那么 range 操作将会一直阻塞,所以通常我们都会关闭这个 channel,好让程序继续执行
值得注意的是,一个 channel 如果没有被关闭,那么 range 操作将会一直阻塞,所以通常我们都会关闭这个 channel,好让程序继续执行,所以当我们控制 channel 的时候,尽可能的还是让发送方去控制 channel 的关闭,不要在接收方去控制。
```go
go func() {
wg1.Wait()
Expand Down Expand Up @@ -1660,7 +1660,7 @@ func worker(id int, in chan Token, out chan Token, number int,fn func(int)) {
if id == (GNumber-1) && number == 1 {
close(sign)
break
}
}
out <- token
number--
}
Expand Down
9 changes: 5 additions & 4 deletions 并发/context/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @Author: shgopher shgopher@gmail.com
* @Date: 2022-11-17 20:40:42
* @LastEditors: shgopher shgopher@gmail.com
* @LastEditTime: 2024-02-24 22:06:06
* @LastEditTime: 2024-02-24 22:26:17
* @FilePath: /GOFamily/并发/context/README.md
* @Description:
*
Expand Down Expand Up @@ -158,7 +158,7 @@ WithCancel 返回 parent context 的一个副本,它自然就是子 context,
- parent context 的 done close 了,然后子 ctx 也要触发 cancel 方法
- parent context cancel 了触发子 ctx cancel 方法

关于第三条,解释一下:
关于第三条,解释一下:(第四条类似)
```go
package main

Expand Down Expand Up @@ -186,10 +186,11 @@ func doWork(ctx context.Context) {
for {
select {
case <-ctx.Done():
// 工作代码
fmt.Println("over")
return
//default:
// fmt.Println("default")
//default:
// fmt.Println("default")
}
}
}
Expand Down
54 changes: 54 additions & 0 deletions 并发/并发优化/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<!--
* @Author: shgopher shgopher@gmail.com
* @Date: 2024-02-26 00:23:06
* @LastEditors: shgopher shgopher@gmail.com
* @LastEditTime: 2024-02-27 23:21:55
* @FilePath: /GOFamily/并发/并发优化/README.md
* @Description:
*
* Copyright (c) 2024 by shgopher, All Rights Reserved.
-->
# go 语言实战项目并发优化
上文我们已经讲解了 goroutine,channel,并发原语,atomic,context,以及 go 的内存模型,内容还是比较多的,我们需要通过实战的项目的优化演进过程来更好的理解并发的最佳实践
## 能不并发就不并发
并发是一个双刃剑,一方面它可以加速程序,另一方面它也增加了程序的复杂度,所以需要在并发和不并发之间做取舍,如果你发现你的程序在不使用并发的时候也能满足你的需求,答应我,不要使用并发,***累活脏活自己干,不要委派给另一个 goroutine 去做所谓的并发工作。***


```go
// bad
func main() {
http.HandleFunc("/", func(w http.ResponseWriter,r *http.Request,)) {
fmt.Fprintln(w,"hello wrold!")
}
go func(){
if err := http.ListenAndServe(":8080",nil);err != nil {
log.Fatal(err)
}
}()

select{}
}
```
在这段代码中,委派一个 goroutine 去启动一个监听服务,又使用 select {} 去阻塞主 goroutine 的运行

确实,这可以满足需求

但是,委派一个后台 goroutine 去执行监听服务没有带来任何有利的收益,反而增加了代码的复杂度,所以我们应该取消委派,主 goroutine 去执行监听即可

```go
// better

func main(){
http.HandleFunc("/", func(w http.ResponseWriter,r *http.Request,)) {
fmt.Fprintln(w,"hello wrold!")
}

if err := http.ListenAndServe(":8080",nil);err != nil {
log.Fatal(err)
}
}
```


## 优先使用 channel + context 的方法去优雅关闭
## 使用方去决定是否并发

0 comments on commit 8ea835e

Please # to comment.