Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
檀越@新空间
Coding Tree
提交
070bdd8d
C
Coding Tree
项目概览
檀越@新空间
/
Coding Tree
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
C
Coding Tree
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
070bdd8d
编写于
10月 09, 2022
作者:
彭世瑜
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
fix
上级
b28d0c5b
变更
11
隐藏空白更改
内联
并排
Showing
11 changed file
with
1106 addition
and
1101 deletion
+1106
-1101
blog/golang/golang-concurrency-Mutex.md
blog/golang/golang-concurrency-Mutex.md
+58
-0
blog/golang/golang-concurrency-Ticker.md
blog/golang/golang-concurrency-Ticker.md
+71
-0
blog/golang/golang-concurrency-Timer.md
blog/golang/golang-concurrency-Timer.md
+150
-0
blog/golang/golang-concurrency-WaitGroup.md
blog/golang/golang-concurrency-WaitGroup.md
+114
-0
blog/golang/golang-concurrency-atomic.md
blog/golang/golang-concurrency-atomic.md
+235
-0
blog/golang/golang-concurrency-channel.md
blog/golang/golang-concurrency-channel.md
+122
-0
blog/golang/golang-concurrency-goroutines.md
blog/golang/golang-concurrency-goroutines.md
+127
-0
blog/golang/golang-concurrency-runtime.md
blog/golang/golang-concurrency-runtime.md
+165
-0
blog/golang/golang-concurrency-select-switch.md
blog/golang/golang-concurrency-select-switch.md
+53
-0
blog/golang/golang-concurrency.md
blog/golang/golang-concurrency.md
+0
-1100
blog/golang/index.md
blog/golang/index.md
+11
-1
未找到文件。
blog/golang/golang-concurrency-Mutex.md
0 → 100644
浏览文件 @
070bdd8d
# Golang 并发编程-Mutex 互斥锁实现同步
Mutex 互斥锁实现同步
示例
```
go
package
main
import
(
"fmt"
"sync"
"time"
)
var
value
=
100
var
wg
sync
.
WaitGroup
var
lock
sync
.
Mutex
func
add
()
{
defer
wg
.
Done
()
lock
.
Lock
()
time
.
Sleep
(
time
.
Millisecond
*
2
)
value
+=
1
fmt
.
Printf
(
"i++: %v
\n
"
,
value
)
lock
.
Unlock
()
}
func
sub
()
{
defer
wg
.
Done
()
lock
.
Lock
()
time
.
Sleep
(
time
.
Millisecond
*
10
)
value
-=
1
fmt
.
Printf
(
"i--: %v
\n
"
,
value
)
lock
.
Unlock
()
}
func
main
()
{
for
i
:=
0
;
i
<
100
;
i
++
{
wg
.
Add
(
1
)
go
add
()
wg
.
Add
(
1
)
go
sub
()
}
wg
.
Wait
()
fmt
.
Printf
(
"end: %v
\n
"
,
value
)
}
```
blog/golang/golang-concurrency-Ticker.md
0 → 100644
浏览文件 @
070bdd8d
# Golang 并发编程-Ticker 周期执行
Timer 只执行一次,Ticker 可以周期的执行
示例
```
go
package
main
import
(
"fmt"
"time"
)
func
main
()
{
// 执行五次打印
ticker
:=
time
.
NewTicker
(
time
.
Second
)
count
:=
0
for
_
=
range
ticker
.
C
{
fmt
.
Println
(
"ticker"
)
count
++
if
count
>=
5
{
ticker
.
Stop
()
break
}
}
}
```
示例
```
go
package
main
import
(
"fmt"
"time"
)
func
main
()
{
ticker
:=
time
.
NewTicker
(
time
.
Second
)
chanInt
:=
make
(
chan
int
)
// 定时向管道随机发送一个数
go
func
()
{
for
_
=
range
ticker
.
C
{
select
{
case
chanInt
<-
1
:
case
chanInt
<-
2
:
case
chanInt
<-
3
:
}
}
}()
// 接收管道数据
sum
:=
0
for
v
:=
range
chanInt
{
fmt
.
Printf
(
"v: %v
\n
"
,
v
)
sum
+=
v
if
sum
>=
10
{
break
}
}
}
```
blog/golang/golang-concurrency-Timer.md
0 → 100644
浏览文件 @
070bdd8d
# Golang 并发编程-Timer定时器
定时器,可以实现一些定时操作,内部通过 channel 实现
示例
```
go
package
main
import
(
"fmt"
"time"
)
func
main
()
{
timer
:=
time
.
NewTimer
(
time
.
Second
*
2
)
fmt
.
Printf
(
"time.Now(): %v
\n
"
,
time
.
Now
())
// time.Now(): 2022-09-29 22:31:16.348683 +0800 CST m=+0.000252176
// 阻塞,直到到达指定时间
c
:=
<-
timer
.
C
fmt
.
Printf
(
"c: %v
\n
"
,
c
)
// c: 2022-09-29 22:31:18.35269 +0800 CST m=+2.004256507
}
```
示例
```
go
package
main
import
(
"fmt"
"time"
)
func
main
()
{
timer
:=
time
.
NewTimer
(
time
.
Second
*
2
)
fmt
.
Printf
(
"time.Now(): %v
\n
"
,
time
.
Now
())
// time.Now(): 2022-09-29 22:32:25.585226 +0800 CST m=+0.000134248
// 阻塞,直到到达指定时间
<-
timer
.
C
fmt
.
Printf
(
"time.Now(): %v
\n
"
,
time
.
Now
())
// time.Now(): 2022-09-29 22:32:27.585439 +0800 CST m=+2.000219266
}
```
示例
```
go
package
main
import
(
"fmt"
"time"
)
func
main
()
{
fmt
.
Printf
(
"time.Now(): %v
\n
"
,
time
.
Now
())
// time.Now(): 2022-09-29 22:34:08.764178 +0800 CST m=+0.000082405
time
.
Sleep
(
time
.
Second
*
2
)
fmt
.
Printf
(
"time.Now(): %v
\n
"
,
time
.
Now
())
// time.Now(): 2022-09-29 22:34:10.765022 +0800 CST m=+2.000924537
}
```
示例
```
go
package
main
import
(
"fmt"
"time"
)
func
main
()
{
fmt
.
Printf
(
"time.Now(): %v
\n
"
,
time
.
Now
())
// time.Now(): 2022-09-29 22:34:41.029391 +0800 CST m=+0.000077713
<-
time
.
After
(
time
.
Second
*
2
)
fmt
.
Printf
(
"time.Now(): %v
\n
"
,
time
.
Now
())
// time.Now(): 2022-09-29 22:34:43.031081 +0800 CST m=+2.001766091
}
```
示例
```
go
package
main
import
(
"fmt"
"time"
)
func
main
()
{
timer
:=
time
.
NewTimer
(
time
.
Second
*
1
)
go
func
()
{
<-
timer
.
C
fmt
.
Println
(
"func"
)
}()
// 停止定时器
stop
:=
timer
.
Stop
()
if
stop
{
fmt
.
Println
(
"stop"
)
}
time
.
Sleep
(
time
.
Second
*
2
)
}
```
示例
```
go
package
main
import
(
"fmt"
"time"
)
func
main
()
{
timer
:=
time
.
NewTimer
(
time
.
Second
*
5
)
// 重新设置定时器时间
timer
.
Reset
(
time
.
Second
*
1
)
<-
timer
.
C
fmt
.
Println
(
"end"
)
}
```
blog/golang/golang-concurrency-WaitGroup.md
0 → 100644
浏览文件 @
070bdd8d
# Golang 并发编程-WaitGroup实现同步
示例1
```
go
package
main
import
(
"fmt"
)
func
showMessage
(
i
int
)
{
fmt
.
Printf
(
"i: %v
\n
"
,
i
)
}
func
main
()
{
for
i
:=
0
;
i
<
10
;
i
++
{
showMessage
(
i
)
}
}
```
输出
```
go
i
:
0
i
:
1
i
:
2
i
:
3
i
:
4
i
:
5
i
:
6
i
:
7
i
:
8
i
:
9
```
示例 2
```
go
package
main
import
(
"fmt"
)
func
showMessage
(
i
int
)
{
fmt
.
Printf
(
"i: %v
\n
"
,
i
)
}
func
main
()
{
for
i
:=
0
;
i
<
10
;
i
++
{
// 启动协程来执行
go
showMessage
(
i
)
}
// 主协程执行结束
fmt
.
Println
(
"end"
)
}
```
输出
```
go
i
:
0
end
```
示例 3
```
go
package
main
import
(
"fmt"
"sync"
)
var
wp
sync
.
WaitGroup
func
showMessage
(
i
int
)
{
defer
wp
.
Done
()
fmt
.
Printf
(
"i: %v
\n
"
,
i
)
}
func
main
()
{
for
i
:=
0
;
i
<
10
;
i
++
{
go
showMessage
(
i
)
wp
.
Add
(
1
)
}
wp
.
Wait
()
fmt
.
Println
(
"end"
)
}
```
输出
```
i: 4
i: 1
i: 0
i: 5
i: 7
i: 8
i: 2
i: 3
i: 9
i: 6
end
```
blog/golang/golang-concurrency-atomic.md
0 → 100644
浏览文件 @
070bdd8d
# Golang 并发编程-atomic原子操作
## 原子变量
不加锁示例
```
go
package
main
import
(
"fmt"
"time"
)
var
value
=
100
func
add
()
{
value
++
}
func
sub
()
{
value
--
}
func
main
()
{
for
i
:=
0
;
i
<
100
;
i
++
{
go
add
()
go
sub
()
}
time
.
Sleep
(
time
.
Second
*
2
)
fmt
.
Printf
(
"value: %v
\n
"
,
value
)
// value: 101
}
```
加锁示例
```
go
package
main
import
(
"fmt"
"sync"
"time"
)
var
value
=
100
var
lock
sync
.
Mutex
func
add
()
{
lock
.
Lock
()
value
++
lock
.
Unlock
()
}
func
sub
()
{
lock
.
Lock
()
value
--
lock
.
Unlock
()
}
func
main
()
{
for
i
:=
0
;
i
<
100
;
i
++
{
go
add
()
go
sub
()
}
time
.
Sleep
(
time
.
Second
*
2
)
fmt
.
Printf
(
"value: %v
\n
"
,
value
)
// value: 100
}
```
atomic示例
cas: compare and swap (old new)
```
go
package
main
import
(
"fmt"
"sync/atomic"
"time"
)
var
value
int32
=
100
func
add
()
{
atomic
.
AddInt32
(
&
value
,
1
)
}
func
sub
()
{
atomic
.
AddInt32
(
&
value
,
-
1
)
}
func
main
()
{
for
i
:=
0
;
i
<
100
;
i
++
{
go
add
()
go
sub
()
}
time
.
Sleep
(
time
.
Second
*
2
)
fmt
.
Printf
(
"value: %v
\n
"
,
value
)
// value: 100
}
```
## 原子操作详解
atomic 提供的原子操作能够确保任一时刻,只有一个goroutine对变量进行操作
善用atomic能够避免程序中出现大量的锁操作
atomic常见的操作有:
-
增减
-
载入 read
-
比较并交换cas
-
交换
-
存储 write
### 增减
```
go
package
main
import
(
"fmt"
"sync/atomic"
)
func
main
()
{
var
value
int32
=
100
atomic
.
AddInt32
(
&
value
,
1
)
fmt
.
Printf
(
"value: %v
\n
"
,
value
)
// value: 101
atomic
.
AddInt32
(
&
value
,
-
1
)
fmt
.
Printf
(
"value: %v
\n
"
,
value
)
// value: 100
}
```
### 读写
```
go
package
main
import
(
"fmt"
"sync/atomic"
)
func
main
()
{
var
value
int32
=
100
// read
atomic
.
LoadInt32
(
&
value
)
fmt
.
Printf
(
"value: %v
\n
"
,
value
)
// value: 100
// write
atomic
.
StoreInt32
(
&
value
,
200
)
fmt
.
Printf
(
"value: %v
\n
"
,
value
)
// value: 200
}
```
### 比较并交换cas
```
go
package
main
import
(
"fmt"
"sync/atomic"
)
func
main
()
{
var
value
int32
=
100
// cas
ret
:=
atomic
.
CompareAndSwapInt32
(
&
value
,
100
,
200
)
fmt
.
Printf
(
"ret: %v
\n
"
,
ret
)
// ret: true
fmt
.
Printf
(
"value: %v
\n
"
,
value
)
// value: 200
}
```
### 交换
```
go
package
main
import
(
"fmt"
"sync/atomic"
)
func
main
()
{
var
value
int32
=
100
// 直接交换
atomic
.
SwapInt32
(
&
value
,
200
)
fmt
.
Printf
(
"value: %v
\n
"
,
value
)
// value: 200
}
```
blog/golang/golang-concurrency-channel.md
0 → 100644
浏览文件 @
070bdd8d
# Golang 并发编程-channel
Go 提供了一种通道机制,用于 goroutine 之间
`共享数据`
通道需要指定
`数据类型`
通道分类:
-
无缓冲通道 同步通讯
-
缓冲通道 异步通讯
语法
```
go
// 整型无缓冲通道,默认零值
Unbuffered
:=
make
(
chan
int
)
// 整型缓冲通道
buffered
:=
make
(
chan
int
,
10
)
```
通道数据交换
```
go
channel
:=
make
(
chan
string
,
5
)
// 将值发送到通道
channel
<-
"hello"
// 从通道接收值
data
:=
<-
channel
```
通道的发送和接收特性
-
同一通道,发送操作之间是互斥的,接收操作之间也是互斥的
-
发送操作和接收操作中对元素值的处理都是不可分割的
-
发送操作在完全完成之前会被阻塞,接收操作也是如此
示例
```
go
package
main
import
(
"fmt"
"math/rand"
"time"
)
// 创建一个int类型的通道
var
value
=
make
(
chan
int
)
func
send
()
{
// 向通道发送一个随机值
rand
.
Seed
(
time
.
Now
()
.
UnixNano
())
v
:=
rand
.
Intn
(
10
)
time
.
Sleep
(
time
.
Second
*
3
)
value
<-
v
}
func
main
()
{
// 关闭通道
defer
close
(
value
)
go
send
()
fmt
.
Println
(
"wait..."
)
// 从通道接收值
v
:=
<-
value
fmt
.
Printf
(
"v: %v
\n
"
,
v
)
}
```
## Channel遍历
示例
```
go
package
main
import
"fmt"
var
c
=
make
(
chan
int
)
func
main
()
{
go
func
()
{
for
i
:=
0
;
i
<
2
;
i
++
{
c
<-
i
}
// 不关闭可能出现死锁
close
(
c
)
}()
// 方式一
// for i := 0; i < 2; i++ {
// v := <-c
// fmt.Printf("v: %v\n", v)
// }
// 方式二
// for v := range c {
// fmt.Printf("v: %v\n", v)
// }
// 方式三
for
{
v
,
ok
:=
<-
c
if
ok
{
fmt
.
Printf
(
"v: %v
\n
"
,
v
)
}
else
{
break
}
}
}
```
blog/golang/golang-concurrency-goroutines.md
0 → 100644
浏览文件 @
070bdd8d
# Golang 并发编程-协程
共语言中的并发是
`函数`
相互独立运行的能力。goroutines 是并发运行的函数
创建协程
```
go
go
task
()
```
示例 1
```
go
package
main
import
(
"fmt"
"time"
)
func
showMessage
(
message
string
)
{
for
i
:=
0
;
i
<
5
;
i
++
{
fmt
.
Println
(
message
)
time
.
Sleep
(
time
.
Millisecond
*
100
)
}
}
func
main
()
{
showMessage
(
"Tom"
)
showMessage
(
"Jack"
)
}
```
输出
```
Tom
Tom
Tom
Tom
Tom
Jack
Jack
Jack
Jack
Jack
```
```
go
func
main
()
{
go
showMessage
(
"Tom"
)
showMessage
(
"Jack"
)
}
```
输出
```
go
Jack
Tom
Tom
Jack
Jack
Tom
Tom
Jack
Jack
Tom
```
示例 2
```
go
package
main
import
(
"fmt"
"io/ioutil"
"log"
"net/http"
"time"
)
func
responseSize
(
url
string
)
{
fmt
.
Println
(
"step1: "
,
url
)
response
,
err
:=
http
.
Get
(
url
)
if
err
!=
nil
{
log
.
Fatal
(
err
)
}
fmt
.
Println
(
"step2: "
,
url
)
defer
response
.
Body
.
Close
()
fmt
.
Println
(
"step3: "
,
url
)
body
,
err
:=
ioutil
.
ReadAll
(
response
.
Body
)
if
err
!=
nil
{
log
.
Fatal
(
err
)
}
fmt
.
Println
(
"step4: "
,
len
(
body
))
}
func
main
()
{
go
responseSize
(
"https://www.baidu.com/"
)
go
responseSize
(
"https://www.jd.com/"
)
go
responseSize
(
"https://www.taobao.com/"
)
time
.
Sleep
(
time
.
Second
*
10
)
}
```
输出
```
step1: https://www.baidu.com/
step1: https://www.jd.com/
step1: https://www.taobao.com/
step2: https://www.jd.com/
step3: https://www.jd.com/
step4: 160260
step2: https://www.baidu.com/
step3: https://www.baidu.com/
step4: 227
step2: https://www.taobao.com/
step3: https://www.taobao.com/
step4: 87347
```
blog/golang/golang-concurrency-runtime.md
0 → 100644
浏览文件 @
070bdd8d
# Golang 并发编程-runtime包
runtime定义了协程管理的包
## Gosched
让出执行权限
示例
```
go
package
main
import
(
"fmt"
)
func
show
()
{
for
i
:=
0
;
i
<
2
;
i
++
{
fmt
.
Printf
(
"show i: %v
\n
"
,
i
)
}
}
func
main
()
{
go
show
()
for
i
:=
0
;
i
<
2
;
i
++
{
fmt
.
Printf
(
"main i: %v
\n
"
,
i
)
}
fmt
.
Println
(
"end"
)
}
```
输出
```
main i: 0
main i: 1
end
```
示例 2
```
go
package
main
import
(
"fmt"
"runtime"
)
func
show
()
{
for
i
:=
0
;
i
<
2
;
i
++
{
fmt
.
Printf
(
"show i: %v
\n
"
,
i
)
}
}
func
main
()
{
go
show
()
for
i
:=
0
;
i
<
2
;
i
++
{
// 让出执行权限,给其他子协程执行
runtime
.
Gosched
()
fmt
.
Printf
(
"main i: %v
\n
"
,
i
)
}
fmt
.
Println
(
"end"
)
}
```
输出
```
show i: 0
main i: 0
main i: 1
end
```
## Goexit
退出当前协程
示例
```
go
package
main
import
(
"fmt"
"runtime"
"time"
)
func
show
()
{
for
i
:=
0
;
i
<
10
;
i
++
{
fmt
.
Printf
(
"show i: %v
\n
"
,
i
)
if
i
>=
5
{
runtime
.
Goexit
()
}
}
}
func
main
()
{
go
show
()
time
.
Sleep
(
time
.
Second
)
fmt
.
Println
(
"end"
)
}
```
输出
```
show i: 0
show i: 1
show i: 2
show i: 3
show i: 4
show i: 5
end
```
## GOMAXPROCS
设置CPU数量
```
go
package
main
import
(
"fmt"
"runtime"
"time"
)
func
show
(
name
string
)
{
for
i
:=
0
;
i
<
10
;
i
++
{
fmt
.
Printf
(
"%v i: %v
\n
"
,
name
,
i
)
}
}
func
main
()
{
// 查看CPU核数
fmt
.
Printf
(
"runtime.NumCPU(): %v
\n
"
,
runtime
.
NumCPU
())
// runtime.NumCPU(): 8
// 设置CPU数量
runtime
.
GOMAXPROCS
(
2
)
go
show
(
"A"
)
go
show
(
"B"
)
time
.
Sleep
(
time
.
Second
)
fmt
.
Println
(
"end"
)
}
```
blog/golang/golang-concurrency-select-switch.md
0 → 100644
浏览文件 @
070bdd8d
# Golang 并发编程-select switch
select 是go中的一个控制结构,类似于switch语句,用于处理异步IO操作
select 会监听case语句中channel的读写操作,当case中channel读写操作为非阻塞状态(即能读写)时,将会触发相应的动作
sekect 中的case语句必须是一个channel操作
select 中的default子句总是可运行的
如果有多个case都可以运行,select会
`随机`
公平地选出一个执行,其他不会执行
如果没有可运行的case语句,且有default语句,那么就会执行default语句
如果没有可运行的case语句,且没有default语句,select将
`阻塞`
,知道某个case通信可以运行
示例
```
go
package
main
import
(
"fmt"
"time"
)
var
chanInt
=
make
(
chan
int
)
var
chanString
=
make
(
chan
string
)
func
main
()
{
go
func
()
{
chanInt
<-
10
chanString
<-
"Tom"
defer
close
(
chanInt
)
defer
close
(
chanString
)
}()
for
{
select
{
case
i
:=
<-
chanInt
:
fmt
.
Printf
(
"int: %v
\n
"
,
i
)
case
i
:=
<-
chanString
:
fmt
.
Printf
(
"string: %v
\n
"
,
i
)
default
:
fmt
.
Println
(
"default"
)
}
time
.
Sleep
(
time
.
Second
)
}
}
```
blog/golang/golang-concurrency.md
已删除
100644 → 0
浏览文件 @
b28d0c5b
# 第二十章 Golang 并发编程
## 协程
共语言中的并发是
`函数`
相互独立运行的能力。goroutines 是并发运行的函数
创建协程
```
go
go
task
()
```
示例 1
```
go
package
main
import
(
"fmt"
"time"
)
func
showMessage
(
message
string
)
{
for
i
:=
0
;
i
<
5
;
i
++
{
fmt
.
Println
(
message
)
time
.
Sleep
(
time
.
Millisecond
*
100
)
}
}
func
main
()
{
showMessage
(
"Tom"
)
showMessage
(
"Jack"
)
}
```
输出
```
Tom
Tom
Tom
Tom
Tom
Jack
Jack
Jack
Jack
Jack
```
```
go
func
main
()
{
go
showMessage
(
"Tom"
)
showMessage
(
"Jack"
)
}
```
输出
```
go
Jack
Tom
Tom
Jack
Jack
Tom
Tom
Jack
Jack
Tom
```
示例 2
```
go
package
main
import
(
"fmt"
"io/ioutil"
"log"
"net/http"
"time"
)
func
responseSize
(
url
string
)
{
fmt
.
Println
(
"step1: "
,
url
)
response
,
err
:=
http
.
Get
(
url
)
if
err
!=
nil
{
log
.
Fatal
(
err
)
}
fmt
.
Println
(
"step2: "
,
url
)
defer
response
.
Body
.
Close
()
fmt
.
Println
(
"step3: "
,
url
)
body
,
err
:=
ioutil
.
ReadAll
(
response
.
Body
)
if
err
!=
nil
{
log
.
Fatal
(
err
)
}
fmt
.
Println
(
"step4: "
,
len
(
body
))
}
func
main
()
{
go
responseSize
(
"https://www.baidu.com/"
)
go
responseSize
(
"https://www.jd.com/"
)
go
responseSize
(
"https://www.taobao.com/"
)
time
.
Sleep
(
time
.
Second
*
10
)
}
```
输出
```
step1: https://www.baidu.com/
step1: https://www.jd.com/
step1: https://www.taobao.com/
step2: https://www.jd.com/
step3: https://www.jd.com/
step4: 160260
step2: https://www.baidu.com/
step3: https://www.baidu.com/
step4: 227
step2: https://www.taobao.com/
step3: https://www.taobao.com/
step4: 87347
```
## channel
Go提供了一种通道机制,用于goroutine之间
`共享数据`
通道需要指定
`数据类型`
通道分类:
-
无缓冲通道 同步通讯
-
缓冲通道 异步通讯
语法
```
go
// 整型无缓冲通道,默认零值
Unbuffered
:=
make
(
chan
int
)
// 整型缓冲通道
buffered
:=
make
(
chan
int
,
10
)
```
通道数据交换
```
go
channel
:=
make
(
chan
string
,
5
)
// 将值发送到通道
channel
<-
"hello"
// 从通道接收值
data
:=
<-
channel
```
通道的发送和接收特性
-
同一通道,发送操作之间是互斥的,接收操作之间也是互斥的
-
发送操作和接收操作中对元素值的处理都是不可分割的
-
发送操作在完全完成之前会被阻塞,接收操作也是如此
示例
```
go
package
main
import
(
"fmt"
"math/rand"
"time"
)
// 创建一个int类型的通道
var
value
=
make
(
chan
int
)
func
send
()
{
// 向通道发送一个随机值
rand
.
Seed
(
time
.
Now
()
.
UnixNano
())
v
:=
rand
.
Intn
(
10
)
time
.
Sleep
(
time
.
Second
*
3
)
value
<-
v
}
func
main
()
{
// 关闭通道
defer
close
(
value
)
go
send
()
fmt
.
Println
(
"wait..."
)
// 从通道接收值
v
:=
<-
value
fmt
.
Printf
(
"v: %v
\n
"
,
v
)
}
```
## WaitGroup实现同步
示例1
```
go
package
main
import
(
"fmt"
)
func
showMessage
(
i
int
)
{
fmt
.
Printf
(
"i: %v
\n
"
,
i
)
}
func
main
()
{
for
i
:=
0
;
i
<
10
;
i
++
{
showMessage
(
i
)
}
}
```
输出
```
go
i
:
0
i
:
1
i
:
2
i
:
3
i
:
4
i
:
5
i
:
6
i
:
7
i
:
8
i
:
9
```
示例 2
```
go
package
main
import
(
"fmt"
)
func
showMessage
(
i
int
)
{
fmt
.
Printf
(
"i: %v
\n
"
,
i
)
}
func
main
()
{
for
i
:=
0
;
i
<
10
;
i
++
{
// 启动协程来执行
go
showMessage
(
i
)
}
// 主协程执行结束
fmt
.
Println
(
"end"
)
}
```
输出
```
go
i
:
0
end
```
示例 3
```
go
package
main
import
(
"fmt"
"sync"
)
var
wp
sync
.
WaitGroup
func
showMessage
(
i
int
)
{
defer
wp
.
Done
()
fmt
.
Printf
(
"i: %v
\n
"
,
i
)
}
func
main
()
{
for
i
:=
0
;
i
<
10
;
i
++
{
go
showMessage
(
i
)
wp
.
Add
(
1
)
}
wp
.
Wait
()
fmt
.
Println
(
"end"
)
}
```
输出
```
i: 4
i: 1
i: 0
i: 5
i: 7
i: 8
i: 2
i: 3
i: 9
i: 6
end
```
## runtime包
runtime定义了协程管理的包
### Gosched
让出执行权限
示例
```
go
package
main
import
(
"fmt"
)
func
show
()
{
for
i
:=
0
;
i
<
2
;
i
++
{
fmt
.
Printf
(
"show i: %v
\n
"
,
i
)
}
}
func
main
()
{
go
show
()
for
i
:=
0
;
i
<
2
;
i
++
{
fmt
.
Printf
(
"main i: %v
\n
"
,
i
)
}
fmt
.
Println
(
"end"
)
}
```
输出
```
main i: 0
main i: 1
end
```
示例 2
```
go
package
main
import
(
"fmt"
"runtime"
)
func
show
()
{
for
i
:=
0
;
i
<
2
;
i
++
{
fmt
.
Printf
(
"show i: %v
\n
"
,
i
)
}
}
func
main
()
{
go
show
()
for
i
:=
0
;
i
<
2
;
i
++
{
// 让出执行权限,给其他子协程执行
runtime
.
Gosched
()
fmt
.
Printf
(
"main i: %v
\n
"
,
i
)
}
fmt
.
Println
(
"end"
)
}
```
输出
```
show i: 0
main i: 0
main i: 1
end
```
### Goexit
退出当前协程
示例
```
go
package
main
import
(
"fmt"
"runtime"
"time"
)
func
show
()
{
for
i
:=
0
;
i
<
10
;
i
++
{
fmt
.
Printf
(
"show i: %v
\n
"
,
i
)
if
i
>=
5
{
runtime
.
Goexit
()
}
}
}
func
main
()
{
go
show
()
time
.
Sleep
(
time
.
Second
)
fmt
.
Println
(
"end"
)
}
```
输出
```
show i: 0
show i: 1
show i: 2
show i: 3
show i: 4
show i: 5
end
```
### GOMAXPROCS
设置CPU数量
```
go
package
main
import
(
"fmt"
"runtime"
"time"
)
func
show
(
name
string
)
{
for
i
:=
0
;
i
<
10
;
i
++
{
fmt
.
Printf
(
"%v i: %v
\n
"
,
name
,
i
)
}
}
func
main
()
{
// 查看CPU核数
fmt
.
Printf
(
"runtime.NumCPU(): %v
\n
"
,
runtime
.
NumCPU
())
// runtime.NumCPU(): 8
// 设置CPU数量
runtime
.
GOMAXPROCS
(
2
)
go
show
(
"A"
)
go
show
(
"B"
)
time
.
Sleep
(
time
.
Second
)
fmt
.
Println
(
"end"
)
}
```
## Mutex 互斥锁实现同步
示例
```
go
package
main
import
(
"fmt"
"sync"
"time"
)
var
value
=
100
var
wg
sync
.
WaitGroup
var
lock
sync
.
Mutex
func
add
()
{
defer
wg
.
Done
()
lock
.
Lock
()
time
.
Sleep
(
time
.
Millisecond
*
2
)
value
+=
1
fmt
.
Printf
(
"i++: %v
\n
"
,
value
)
lock
.
Unlock
()
}
func
sub
()
{
defer
wg
.
Done
()
lock
.
Lock
()
time
.
Sleep
(
time
.
Millisecond
*
10
)
value
-=
1
fmt
.
Printf
(
"i--: %v
\n
"
,
value
)
lock
.
Unlock
()
}
func
main
()
{
for
i
:=
0
;
i
<
100
;
i
++
{
wg
.
Add
(
1
)
go
add
()
wg
.
Add
(
1
)
go
sub
()
}
wg
.
Wait
()
fmt
.
Printf
(
"end: %v
\n
"
,
value
)
}
```
## Channel遍历
示例
```
go
package
main
import
"fmt"
var
c
=
make
(
chan
int
)
func
main
()
{
go
func
()
{
for
i
:=
0
;
i
<
2
;
i
++
{
c
<-
i
}
// 不关闭可能出现死锁
close
(
c
)
}()
// 方式一
// for i := 0; i < 2; i++ {
// v := <-c
// fmt.Printf("v: %v\n", v)
// }
// 方式二
// for v := range c {
// fmt.Printf("v: %v\n", v)
// }
// 方式三
for
{
v
,
ok
:=
<-
c
if
ok
{
fmt
.
Printf
(
"v: %v
\n
"
,
v
)
}
else
{
break
}
}
}
```
## select switch
select 是go中的一个控制结构,类似于switch语句,用于处理异步IO操作
select 会监听case语句中channel的读写操作,当case中channel读写操作为非阻塞状态(即能读写)时,将会触发相应的动作
sekect 中的case语句必须是一个channel操作
select 中的default子句总是可运行的
如果有多个case都可以运行,select会
`随机`
公平地选出一个执行,其他不会执行
如果没有可运行的case语句,且有default语句,那么就会执行default语句
如果没有可运行的case语句,且没有default语句,select将
`阻塞`
,知道某个case通信可以运行
示例
```
go
package
main
import
(
"fmt"
"time"
)
var
chanInt
=
make
(
chan
int
)
var
chanString
=
make
(
chan
string
)
func
main
()
{
go
func
()
{
chanInt
<-
10
chanString
<-
"Tom"
defer
close
(
chanInt
)
defer
close
(
chanString
)
}()
for
{
select
{
case
i
:=
<-
chanInt
:
fmt
.
Printf
(
"int: %v
\n
"
,
i
)
case
i
:=
<-
chanString
:
fmt
.
Printf
(
"string: %v
\n
"
,
i
)
default
:
fmt
.
Println
(
"default"
)
}
time
.
Sleep
(
time
.
Second
)
}
}
```
## Timer
定时器,可以实现一些定时操作,内部通过channel实现
示例
```
go
package
main
import
(
"fmt"
"time"
)
func
main
()
{
timer
:=
time
.
NewTimer
(
time
.
Second
*
2
)
fmt
.
Printf
(
"time.Now(): %v
\n
"
,
time
.
Now
())
// time.Now(): 2022-09-29 22:31:16.348683 +0800 CST m=+0.000252176
// 阻塞,直到到达指定时间
c
:=
<-
timer
.
C
fmt
.
Printf
(
"c: %v
\n
"
,
c
)
// c: 2022-09-29 22:31:18.35269 +0800 CST m=+2.004256507
}
```
示例
```
go
package
main
import
(
"fmt"
"time"
)
func
main
()
{
timer
:=
time
.
NewTimer
(
time
.
Second
*
2
)
fmt
.
Printf
(
"time.Now(): %v
\n
"
,
time
.
Now
())
// time.Now(): 2022-09-29 22:32:25.585226 +0800 CST m=+0.000134248
// 阻塞,直到到达指定时间
<-
timer
.
C
fmt
.
Printf
(
"time.Now(): %v
\n
"
,
time
.
Now
())
// time.Now(): 2022-09-29 22:32:27.585439 +0800 CST m=+2.000219266
}
```
示例
```
go
package
main
import
(
"fmt"
"time"
)
func
main
()
{
fmt
.
Printf
(
"time.Now(): %v
\n
"
,
time
.
Now
())
// time.Now(): 2022-09-29 22:34:08.764178 +0800 CST m=+0.000082405
time
.
Sleep
(
time
.
Second
*
2
)
fmt
.
Printf
(
"time.Now(): %v
\n
"
,
time
.
Now
())
// time.Now(): 2022-09-29 22:34:10.765022 +0800 CST m=+2.000924537
}
```
示例
```
go
package
main
import
(
"fmt"
"time"
)
func
main
()
{
fmt
.
Printf
(
"time.Now(): %v
\n
"
,
time
.
Now
())
// time.Now(): 2022-09-29 22:34:41.029391 +0800 CST m=+0.000077713
<-
time
.
After
(
time
.
Second
*
2
)
fmt
.
Printf
(
"time.Now(): %v
\n
"
,
time
.
Now
())
// time.Now(): 2022-09-29 22:34:43.031081 +0800 CST m=+2.001766091
}
```
示例
```
go
package
main
import
(
"fmt"
"time"
)
func
main
()
{
timer
:=
time
.
NewTimer
(
time
.
Second
*
1
)
go
func
()
{
<-
timer
.
C
fmt
.
Println
(
"func"
)
}()
// 停止定时器
stop
:=
timer
.
Stop
()
if
stop
{
fmt
.
Println
(
"stop"
)
}
time
.
Sleep
(
time
.
Second
*
2
)
}
```
示例
```
go
package
main
import
(
"fmt"
"time"
)
func
main
()
{
timer
:=
time
.
NewTimer
(
time
.
Second
*
5
)
// 重新设置定时器时间
timer
.
Reset
(
time
.
Second
*
1
)
<-
timer
.
C
fmt
.
Println
(
"end"
)
}
```
## Ticker
Timer只执行一次,Ticker可以周期的执行
示例
```
go
package
main
import
(
"fmt"
"time"
)
func
main
()
{
// 执行五次打印
ticker
:=
time
.
NewTicker
(
time
.
Second
)
count
:=
0
for
_
=
range
ticker
.
C
{
fmt
.
Println
(
"ticker"
)
count
++
if
count
>=
5
{
ticker
.
Stop
()
break
}
}
}
```
示例
```
go
package
main
import
(
"fmt"
"time"
)
func
main
()
{
ticker
:=
time
.
NewTicker
(
time
.
Second
)
chanInt
:=
make
(
chan
int
)
// 定时向管道随机发送一个数
go
func
()
{
for
_
=
range
ticker
.
C
{
select
{
case
chanInt
<-
1
:
case
chanInt
<-
2
:
case
chanInt
<-
3
:
}
}
}()
// 接收管道数据
sum
:=
0
for
v
:=
range
chanInt
{
fmt
.
Printf
(
"v: %v
\n
"
,
v
)
sum
+=
v
if
sum
>=
10
{
break
}
}
}
```
## 原子变量
不加锁示例
```
go
package
main
import
(
"fmt"
"time"
)
var
value
=
100
func
add
()
{
value
++
}
func
sub
()
{
value
--
}
func
main
()
{
for
i
:=
0
;
i
<
100
;
i
++
{
go
add
()
go
sub
()
}
time
.
Sleep
(
time
.
Second
*
2
)
fmt
.
Printf
(
"value: %v
\n
"
,
value
)
// value: 101
}
```
加锁示例
```
go
package
main
import
(
"fmt"
"sync"
"time"
)
var
value
=
100
var
lock
sync
.
Mutex
func
add
()
{
lock
.
Lock
()
value
++
lock
.
Unlock
()
}
func
sub
()
{
lock
.
Lock
()
value
--
lock
.
Unlock
()
}
func
main
()
{
for
i
:=
0
;
i
<
100
;
i
++
{
go
add
()
go
sub
()
}
time
.
Sleep
(
time
.
Second
*
2
)
fmt
.
Printf
(
"value: %v
\n
"
,
value
)
// value: 100
}
```
atomic示例
cas: compare and swap (old new)
```
go
package
main
import
(
"fmt"
"sync/atomic"
"time"
)
var
value
int32
=
100
func
add
()
{
atomic
.
AddInt32
(
&
value
,
1
)
}
func
sub
()
{
atomic
.
AddInt32
(
&
value
,
-
1
)
}
func
main
()
{
for
i
:=
0
;
i
<
100
;
i
++
{
go
add
()
go
sub
()
}
time
.
Sleep
(
time
.
Second
*
2
)
fmt
.
Printf
(
"value: %v
\n
"
,
value
)
// value: 100
}
```
## 原子操作详解
atomic 提供的原子操作能够确保任一时刻,只有一个goroutine对变量进行操作
善用atomic能够避免程序中出现大量的锁操作
atomic常见的操作有:
-
增减
-
载入 read
-
比较并交换cas
-
交换
-
存储 write
### 增减
```
go
package
main
import
(
"fmt"
"sync/atomic"
)
func
main
()
{
var
value
int32
=
100
atomic
.
AddInt32
(
&
value
,
1
)
fmt
.
Printf
(
"value: %v
\n
"
,
value
)
// value: 101
atomic
.
AddInt32
(
&
value
,
-
1
)
fmt
.
Printf
(
"value: %v
\n
"
,
value
)
// value: 100
}
```
### 读写
```
go
package
main
import
(
"fmt"
"sync/atomic"
)
func
main
()
{
var
value
int32
=
100
// read
atomic
.
LoadInt32
(
&
value
)
fmt
.
Printf
(
"value: %v
\n
"
,
value
)
// value: 100
// write
atomic
.
StoreInt32
(
&
value
,
200
)
fmt
.
Printf
(
"value: %v
\n
"
,
value
)
// value: 200
}
```
### 比较并交换cas
```
go
package
main
import
(
"fmt"
"sync/atomic"
)
func
main
()
{
var
value
int32
=
100
// cas
ret
:=
atomic
.
CompareAndSwapInt32
(
&
value
,
100
,
200
)
fmt
.
Printf
(
"ret: %v
\n
"
,
ret
)
// ret: true
fmt
.
Printf
(
"value: %v
\n
"
,
value
)
// value: 200
}
```
### 交换
```
go
package
main
import
(
"fmt"
"sync/atomic"
)
func
main
()
{
var
value
int32
=
100
// 直接交换
atomic
.
SwapInt32
(
&
value
,
200
)
fmt
.
Printf
(
"value: %v
\n
"
,
value
)
// value: 200
}
```
blog/golang/index.md
浏览文件 @
070bdd8d
...
...
@@ -46,7 +46,17 @@
[
第十九章 Golang包 package
](
/blog/golang/golang-package.md
)
[
第二十章 Golang 并发编程
](
/blog/golang/golang-concurrency.md
)
第二十章 Golang 并发编程
-
[
Golang 并发编程-协程
](
/blog/golang/golang-concurrency-goroutines.md
)
-
[
Golang 并发编程-channel
](
/blog/golang/golang-concurrency-channel.md
)
-
[
Golang 并发编程-WaitGroup实现同步
](
/blog/golang/golang-concurrency-WaitGroup.md
)
-
[
Golang 并发编程-runtime包
](
/blog/golang/golang-concurrency-runtime.md
)
-
[
Golang 并发编程-Mutex 互斥锁实现同步
](
/blog/golang/golang-concurrency-Mutex.md
)
-
[
Golang 并发编程-atomic原子操作
](
/blog/golang/golang-concurrency-atomic.md
)
-
[
Golang 并发编程-select switch
](
/blog/golang/golang-concurrency-select-switch.md
)
-
[
Golang 并发编程-Timer定时器
](
/blog/golang/golang-concurrency-Timer.md
)
-
[
Golang 并发编程-Ticker 周期执行
](
/blog/golang/golang-concurrency-Ticker.md
)
第二十一章 Golang标准库
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录