package main
import (
"fmt"
"math/rand"
"sync"
"sync/atomic"
"time"
)
func example1() {
//不要这样写,阻塞就死无法解除,零值nil
var c1 chan int
fmt.Printf("%d,%d,%v", len(c1), cap(c1), c1)
//c1 <- 1 //阻塞不报错,由于没有初始化容器,1塞不进去,死锁。
<-c1 //也阻塞,什么都拿不出来,死锁
fmt.Println("111111") //上面阻塞了死锁了 这个是不能打印出来的
}
func example2() {
//通过make创建
//非缓冲通道,容量为0,也叫同步通道。发送第一个元素时,如果没有接收操作就立即阻塞,知道接收,同样接收时,如果没有数据发送就立即阻塞,知道数据发送
c2 := make(chan int, 0)
c3 := make(chan int)
fmt.Printf("c2: %d,%d,%v\n", len(c2), cap(c2), c2) //c2: 0,0,0xc0000103c0
fmt.Printf("c3: %d,%d,%v\n", len(c3), cap(c3), c3) //c3: 0,0,0xc000010420
//缓冲通道
c4 := make(chan int, 8)
fmt.Printf("c4: %d,%d,%v\n", len(c4), cap(c4), c4) //c4: 0,8,0xc0000240a0
//往通道发送数据
c4 <- 1
c4 <- 2
fmt.Printf("c4: %d,%d,%v\n", len(c4), cap(c4), c4) //c4: 2,8,0xc0000240a0
//从通道拿数据接收数据
<-c4 //拿走,扔了
t := <-c4 //拿出来赋值给t
fmt.Printf("%T,%[1]v", t) //int,2
}
//单项通道 chan<- type 只往一个chan里面写,<-chan type 只从chan里面拿
func produce(ch chan<- int) {
for {
ch <- rand.Intn(10)
time.Sleep(time.Second)
//关闭通道,只有发送方才能关闭,一旦关闭,在发送数据就panic,
//如果去掉for,通道只有一个数据,关闭通道,接收者依然可以访问关闭的通道而不阻塞,
//t,ok :=<-ch获取数据失败,ok为false,返回零值
//close(ch) //如果再次关闭直接panic
}
}
func consume(ch <-chan int) {
for {
t, ok := <-ch
fmt.Println("包子被吃了,id:", t, ok)
}
}
func example3() {
//等待组
var wg sync.WaitGroup
wg.Add(1)
fmt.Println("准备吃包子了")
c := make(chan int)
go produce(c)
go consume(c)
wg.Wait()
}
func example4() {
//遍历通道
//缓冲的关闭的通道
c1 := make(chan int, 5)
c1 <- 1
c1 <- 2
c1 <- 3
close(c1)
fmt.Println(<-c1, "故意从通道放走一个")
for v := range c1 {
fmt.Println(v)
}
fmt.Println("end,不关闭通道,你看不见我")
}
func example5() {
//1、非缓冲的未关闭的通道
//相当于一个无限元素的通道,迭代不完,阻塞在等下一个元素到达
//2、非缓冲关闭的通道
//关闭后,通道不能在进入新的元素,那么相当于遍历有限个元素容器,遍历完就结束了
c1 := make(chan int) //非缓冲通道
go func() {
defer close(c1)
count := 1
for i := 0; i < 5; i++ {
time.Sleep(3 * time.Second)
c1 <- count
count++
}
}()
for v := range c1 {
fmt.Println("v print:", v)
}
fmt.Println("不关闭通道,我就死锁,你就看不到我")
}
func example6() {
//定时器
go func() {
t := time.NewTicker(2 * time.Second) //定义2秒的定时器
for {
fmt.Println("我是Ticker定时器阻塞2s的:", <-t.C) //通道阻塞住每隔2秒就接收一次
}
}()
go func() {
t := time.NewTimer(5 * time.Second)
for {
fmt.Println("Timer我开始了")
fmt.Println("我是Timer定时器阻塞5s的:", <-t.C) //通道阻塞5s后只接收一次,再来就阻塞住
fmt.Println("Timer我接收完了")
}
fmt.Println("Timer我接收完了,但我不会打印出来")
}()
time.Sleep(100 * time.Second)
}
func example7() {
//通道死锁
c1 := make(chan int)
c1 <- 1 //当前协程阻塞。无人能解。死锁
}
func example8() {
//struct{}型通道
//如果一个结构体类型就是struct{},说明该结构体的实例没有数据成员,也就是实例内存占用为0,节约内存,仅仅是为了传递一个信号标志
flag := make(chan struct{}) //比chan bool生内存
go func() {
time.Sleep(3 * time.Second)
flag <- struct{}{} //无数据成员的结构体实例
}()
fmt.Printf("等到了信号,%T,%[1]v\n", flag)
}
func example9() {
//通道多路复用
count := make(chan int, 4)
fin := make(chan struct{})
go func() {
defer func() {
fin <- struct{}{}
}()
for i := 0; i < 10; i++ {
count <- i
time.Sleep(time.Second)
}
}()
for {
select {
case n := <-count:
fmt.Println("count:", n)
case <-fin:
fmt.Println("收到退出信号,跳出循环")
goto END
}
}
END:
fmt.Println("我跳出来了")
}
func inc(count *int64) {
for i := 0; i < 100000; i++ {
*count += 1
}
}
func inc2(count *int64, wg *sync.WaitGroup) {
defer wg.Done()
for i := 0; i < 100000; i++ {
*count += 1
}
}
func inc3(count *int64, wg *sync.WaitGroup) {
defer wg.Done()
for i := 0; i < 100000; i++ {
atomic.AddInt64(count, 1)
}
}
func inc4(count *int64, mx *sync.Mutex, wg *sync.WaitGroup) {
defer wg.Done()
for i := 0; i < 100000; i++ {
mx.Lock()
*count++
mx.Unlock()
}
}
func inc5(wg *sync.WaitGroup, ch chan int64) {
defer wg.Done()
for i := 0; i < 100000; i++ {
t := <-ch
t++
ch <- t
}
}
func example10() {
//通道并发 锁,加了锁会影响并行效率保证了逻辑正确
var count int64 = 0
start := time.Now()
//串行没有并发的时候
//inc(&count)
//inc(&count)
//inc(&count)
//inc(&count)
//inc(&count)
// //fmt.Printf("Go协程数:%d\n", runtime.NumGoroutine())
//fmt.Printf("执行了%dms,count is:%d\n", time.Since(start).Microseconds(), count) //执行了1590ms count正确
//for i := 0; i < 5; i++ {
// go inc(&count)
// // //fmt.Printf("Go协程数:%d\n", runtime.NumGoroutine())
//}
//fmt.Printf("执行了%dms,count is:%d\n", time.Since(start).Microseconds(), count) //执行了0-541ms count不对
//var wg sync.WaitGroup
//wg.Add(5)
//for i := 0; i < 5; i++ {
// go inc2(&count, &wg)
//}
//// fmt.Printf("Go协程数:%d\n", runtime.NumGoroutine())
//wg.Wait()
//fmt.Printf("执行了%dms,count is:%d\n", time.Since(start).Microseconds(), count) //执行了512ms,count is:14466
////上面两个例子加了go协程后 最终得到结果完全不对,原因是count++不是原子操作,会被打断。1、原子操作 2、加锁保证结果正确
//==================原子操作
//var wg sync.WaitGroup
//wg.Add(5)
//for i := 0; i < 5; i++ {
// go func() {
// defer wg.Done()
// for i := 0; i < 100000; i++ {
// atomic.AddInt64(&count, 1)
// }
// }()
// //或者把上面的匿名函数扔出去,把count和wg传进去
// //go inc3(&count, &wg)
//}
//wg.Wait()
//fmt.Printf("执行了%dms,count is:%d\n", time.Since(start).Microseconds(), count) //12705ms count:500000
//=======互斥锁
//var wg sync.WaitGroup
//var mx sync.Mutex
//wg.Add(5)
//for i := 0; i < 5; i++ {
// go inc4(&count, &mx, &wg)
//}
////fmt.Printf("Go协程数:%d\n", runtime.NumGoroutine())
//wg.Wait()
//fmt.Printf("执行了%dms,count is:%d\n", time.Since(start).Microseconds(), count) //执行了44866ms,count is:500000
//======使用管道
var wg sync.WaitGroup
ch := make(chan int64, 1)
ch <- 0
wg.Add(5)
for i := 0; i < 5; i++ {
go inc5(&wg, ch)
}
wg.Wait()
fmt.Println(count)
fmt.Printf("执行了%dms,count is:%d\n", time.Since(start).Microseconds(), <-ch) //执行了297097ms,count is:500000
}
func main() {
//example1()
//example2()
//example3()
//time.Sleep(100 * time.Second) //如果开了协程,主协程运行完程序就结束了,笨方法是sleep一会;第二个方法加等待组
//example4()
//example5()
//example6()
//example7()
//example8()
//example9()
example10()
}