同步
突发奇想,想到之前学java的时候,看过一个抢票的列子,然后对线程有了个大概的了解。我也模仿一下,来讲一下goroutine。哈哈哈
goroutine 就是类似于 java中的线程,执行速度极快,不加个sleep,你完全看不到goroutine的输出。
我在下面代码 加了sleep等待1秒钟。
```go
func main() {
const err = false
ch := make(chan string, 2) //加个缓存,防止阻塞
var food = []string{"饼干", "可乐", "夹心饼", "奶酪", "雪碧", "火龙果", "冰镇西瓜", "火鸡面", "土司", "冰淇淋"}
go func(ch <-chan string) {
for c := range ch {
fmt.Println("Mr.Cheese 抢到了 ", c)
}
}(ch)
go func(ch <-chan string) {
for c := range ch {
fmt.Println("Mr.Potato 抢到了 ", c)
}
}(ch)
for _, v := range food {
ch <- v
}
close(ch)
time.Sleep(1* time.Second) // 等待1秒!!!
}
--------------------------------------
输出结果:
Mr.Potato 抢到 饼干
Mr.Cheese 抢到 可乐
Mr.Potato 抢到 夹心饼
Mr.Potato 抢到 奶酪
Mr.Cheese 抢到 雪碧
Mr.Cheese 抢到 火龙果
Mr.Potato 抢到 冰镇西瓜
Mr.Potato 抢到 土司
Mr.Cheese 抢到 火鸡面
Mr.Cheese 抢到 冰淇淋
```
当ch<-v 写入数据时(可以写满2个,因为指定了缓存),此时是等待被goroutine中的读取(<-ch),整个过程,互相争夺的过程。
互斥锁
一个没有互斥锁的列子
```go
func main() {
food :=[]string {"西瓜","巧克力","蛋糕","土司","饼干"}
go func() {
food[0] = "哈密瓜"
fmt.Println("我把西瓜换成了哈密瓜",food)
}()
go func() {
food[0] = "火龙果"
fmt.Println("我把西瓜换成了火龙果",food)
}()
go func() {
food[0] = "榴莲"
fmt.Println("我把西瓜换成了榴莲",food)
}()
time.Sleep(1e9)
}
------------------------------------------
输出结果:
协程B:我把西瓜换成了火龙果 [榴莲 巧克力 蛋糕 土司 饼干]
协程A:我把西瓜换成了哈密瓜 [榴莲 巧克力 蛋糕 土司 饼干]
协程C:我把西瓜换成了榴莲 [榴莲 巧克力 蛋糕 土司 饼干]
```
协程B和协程A,并没有换到自己心仪的食物,为了保证每个协程能换成自己的心仪的食物。如下
一个有互斥锁的列子
```go
func main() {
mutex := sync.Mutex{}
wg := wg.waitGroup()
wg2 := wg.waitGroup()
wa.add(1)
wa2.add(3)
food :=[]string {"西瓜","巧克力","蛋糕","土司","饼干"}
go func() { //协程a
mutex.Lock()
food[0] = "哈密瓜"
fmt.Println("协程A:我把西瓜换成了哈密瓜",food)
mutex.Unlock()
wg2.Done()
}()
go func() { //协程b
mutex.Lock()
food[0] = "火龙果"
fmt.Println("协程B:我把西瓜换成了火龙果",food)
mutex.Unlock()
wg2.Done()
}()
go func() { //协程c
mutex.Lock()
food[0] = "榴莲"
fmt.Println("协程C:我把西瓜换成了榴莲",food)
mutex.Unlock()
wg2.Done()
}()
time.Sleep(1e9)
wg.Done()
wg2.Wait()
}
---------------------------------
输出结果:
协程A:我把西瓜换成了哈密瓜 [哈密瓜 巧克力 蛋糕 土司 饼干]
协程B:我把西瓜换成了火龙果 [火龙果 巧克力 蛋糕 土司 饼干]
协程C:我把西瓜换成了榴莲 [榴莲 巧克力 蛋糕 土司 饼干]
```
锁能保证每个协程能够对数据修改,其它协程必须得等待,直到释放锁。其它协程抢占资源,执行Lock()到unlock的过程。
> 溜了 溜了~~
func main() {
const err = false
ch := make(chan string, 2) //加个缓存,防止阻塞
var food = []string{"饼干", "可乐", "夹心饼", "奶酪", "雪碧", "火龙果", "冰镇西瓜", "火鸡面", "土司", "冰淇淋"}
go func(ch <-chan string) {
for c := range ch {
fmt.Println("Mr.Cheese 抢到了 ", c)
}
}(ch)
go func(ch <-chan string) {
for c := range ch {
fmt.Println("Mr.Potato 抢到了 ", c)
}
}(ch)
for _, v := range food {
ch <- v
}
close(ch)
time.Sleep(1* time.Second) // 等待1秒!!!
}
#2
更多评论
1、第一个例子中每往Chan写一个数据,就有二个GO从里面读数据,导致你最后在关闭时,还有一半的GO没正常关闭。正常的程序不应该这样写,导致GO泄漏
2、由于你的例子中是顺序开启这些GO,所以他们的顺序是确定的。虽然,实际中有可能会发生竞争,但是可能性比较小。
建议修改如下
#1
func main() {
mutex := sync.Mutex{}
wg := new(sync.WaitGroup)
wg2 := new(sync.WaitGroup)
food := []string{"西瓜", "巧克力", "蛋糕", "土司", "饼干"}
wg.Add(1)
wg2.Add(3)
go func() { //协程a
wg.Wait()
mutex.Lock()
food[0] = "哈密瓜"
fmt.Println("协程A:我把西瓜换成了哈密瓜", food)
mutex.Unlock()
wg2.Done()
}()
go func() { //协程b
wg.Wait()
mutex.Lock()
food[0] = "火龙果"
fmt.Println("协程B:我把西瓜换成了火龙果", food)
mutex.Unlock()
wg2.Done()
}()
go func() { //协程c
wg.Wait()
mutex.Lock()
food[0] = "榴莲"
fmt.Println("协程C:我把西瓜换成了榴莲", food)
mutex.Unlock()
wg2.Done()
}()
wg.Done()
wg2.Wait()
}
#3