## 一、概念
* go中channel實現了同步,確保并發安全,同時也提供了鎖的操作方式
* go中sync包提供了鎖相關的支持
* Mutex:以加鎖方式解決并發安全問題
* sync.WaitGroup:用來等待一組子協程的結束,需要設置等待的個數,每個子協程結束后要調用Done(),最后在主協程中Wait()即可。
Add():添加計數
Done():操作結束時調用,計數減1
Wait():等待所有操作結束
## 二、加鎖與不加鎖的區別
#### 不加鎖
~~~
package main
import (
"time"
"fmt"
)
//賬戶
type Account struct {
money int
}
//模擬安全校驗的
func (a *Account) Check() {
time.Sleep(time.Second)
}
//設置余額
func (a *Account) SetAccount(n int) {
a.money += n
}
//查詢余額
func (a *Account) GetAccount() int {
return a.money
}
//買東西
func (a *Account) Buy(n int) {
if a.money > n {
a.Check()
a.money -= n
}
}
func main() {
var account Account
account.SetAccount(100)
//開2個協程買東西
go account.Buy(60)
go account.Buy(50)
time.Sleep(2 * time.Second)
fmt.Println(account.GetAccount())
}
~~~
運行結果
-10
#### 加鎖
~~~
package main
import (
"time"
"fmt"
"sync"
)
//賬戶
type Account struct {
money int
flag sync.Mutex //設置鎖
}
//模擬安全校驗的
func (a *Account) Check() {
time.Sleep(time.Second)
}
//設置余額
func (a *Account) SetAccount(n int) {
a.money += n
}
//查詢余額
func (a *Account) GetAccount() int {
return a.money
}
//買東西
func (a *Account) Buy(n int) {
//加鎖
a.flag.Lock()
if a.money > n {
a.Check()
a.money -= n
}
//解鎖
a.flag.Unlock()
}
func main() {
var account Account
account.SetAccount(100)
//開2個協程買東西
go account.Buy(60)
go account.Buy(50)
time.Sleep(2 * time.Second)
fmt.Println(account.GetAccount())
}
~~~
執行結果:
50
## 三、如果主協程中沒有內容子協程就不會去執行
#### 主協程沒有內容
~~~
package main
import (
"fmt"
)
func main() {
go func() {
fmt.Println("子協程1")
}()
go func() {
fmt.Println("子協程2")
}()
}
~~~
運行結果:
#### 解決原理
~~~
package main
import (
"fmt"
)
func main() {
m1 := make(chan int)
// 子協程活動個數
count :=2
go func() {
fmt.Println("子協程1")
// 協程1結束,發出信號
m1 <- 1
}()
go func() {
fmt.Println("子協程2")
// 協程2結束,發出信號
m1 <- 1
}()
for range m1{
//讀一個數據 count-1
count --
if count ==0{
close(m1)
}
}
}
~~~
執行結果:
子協程2運行
子協程1運行
#### 使用 sync.WaitGroup 解決
~~~
package main
import (
"sync"
"fmt"
)
func main() {
//聲明等待組
var wg sync.WaitGroup
wg.Add(2)
go func() {
fmt.Println("子協程1運行")
wg.Done()
}()
go func() {
fmt.Println("子協程2運行")
wg.Done()
}()
wg.Wait()
}
~~~
執行結果:
子協程2運行
子協程1運行
- 一、數組
- 二、切片
- 三、copy
- 四、MAP
- 五、結構體
- 六、結構體參數
- 七、面向”對象“
- 1、匿名字段
- 2、方法
- 3、包和封裝
- 4、接口
- 5、異常處理
- 八、Json
- 九、文件操作
- 1、寫文件
- 2、讀取文件內容
- 3、拷貝文件
- 十、反射
- 1、查看類型,字段和方法
- 2、查看匿名字段
- 3、修改基本類型的值
- 4、修改結構體的值
- 5、調用方法
- 十一、并發編程
- 1、并行和并發
- 2、協程
- 3、runtime包
- 5、channel的使用
- 6、close
- 7、定時器
- 8、select
- 9、協程同步鎖
- 十二、socket編程
- 十三、Http編程
- 十四、并發爬蟲和數據處理
- 1、簡易爬蟲實例
- 2、并發爬取圖片
- 3、讀文件中的數據
- 4、數據清洗
- 其他
- 1、推薦文章