GO的哲学是“不要通过共享内存来通信,而是通过通信来共享内存”,通道是GO通过通信来共享内存的载体。
创新互联建站-专业网站定制、快速模板网站建设、高性价比彭阳网站开发、企业建站全套包干低至880元,成熟完善的模板库,直接使用。一站式彭阳网站制作公司更省心,省钱,快速模板网站建设找我们,业务覆盖彭阳地区。费用合理售后完善,10余年实体公司更值得信赖。
runtime.NumGoroutine() //返回当前程序的协程数量
runtime.GOMAXPROCS(0) //获取当前的GOMAXPROCS数量
runtime.GOMAXPROCS(2) //设置程序的GOMAXPROCS数量为2
特性
fun main() {
//另起一个协程去打印
go func() {
fmt.Println("goruntine")
}()
}
//创建chan
c := make(chan dataType)
//无缓冲, len 和 cap 都是0
fmt.Println(len(c)) //0
fmt.Println(cap(c)) //0
//有缓冲
c = make(chan dataType, 10)
//len 代表没有被读取的元素数, cap 代表整个通道的容量
fmt.Println(len(c)) //0
fmt.Println(cap(c)) //10
Add(10) 给内置计数器加10
Done() 相当于Add(-1)
Wait() 内置计数器不为0则一直等待
// 写法
func main() {
var wg sync.WaitGroup
wg.Add(10)
for i := 0; i < 10; i++ {
go func(i int) {
defer wg.Done()
fmt.Println(i)
time.Sleep(time.Millisecond * 3000)
}(i)
}
wg.Wait()
fmt.Println("done")
}
看一段融合了并发,缓冲,退出通知等多重特性的代码
func GenerateA(done chan struct{}) chan int {
ch := make(chan int, 5)
// fmt.Println("通道数+1")
go func() {
fmt.Println("线程数+A")
Label:
for {
select {
case res := <-done:
fmt.Println("done", res)
break Label
case ch <- rand.Int():
}
}
close(ch)
}()
return ch
}
func GenerateB(done chan struct{}) chan int {
ch := make(chan int, 5)
go func() {
fmt.Println("线程数+B")
Label:
for {
select {
case res := <-done:
fmt.Println("done", res)
break Label
case ch <- rand.Int():
}
}
close(ch)
}()
return ch
}
func GenerateInt(done chan struct{}) chan int {
//无缓冲通道
ch := make(chan int)
send := make(chan struct{})
go func() {
Label:
for {
select {
case <-done:
send <- struct{}{}
send <- struct{}{}
break Label
case ch <- <-GenerateA(send):
fmt.Println("chose A")
case ch <- <-GenerateB(send):
fmt.Println("chose B")
}
}
close(ch)
}()
return ch
}
func main() {
done := make(chan struct{})
ch := GenerateInt(done)
fmt.Println(runtime.NumGoroutine())
for i := 0; i < 10; i++ {
fmt.Println(<-ch)
}
fmt.Println(runtime.NumGoroutine())
done <- struct{}{}
fmt.Println("stop gernate", struct{}{})
time.Sleep(1 * time.Second) //等待1s,让停止的goruntime打印,如果不加这句话,可能会导致主线程比新起的协程早退出,从而无法打印出done {}
}
打印结果不展示,其中发现的问题:
1.打印出来的数字长度不固定
2.每次Select查看case是否堵塞的时候,都会执行一次该方法
func main() {
ctxa, cancel := context.WithCancel(context.Background())
go work(ctxa, "work1")
tm := time.Now().Add(3 * time.Second)
ctxb, _ := context.WithDeadline(ctxa, tm)
go work(ctxb, "work2")
oc := OtherContext{ctxb}
ctxc := context.WithValue(oc, "key", "andes, pass from main")
go workWithValue(ctxc, "work3")
time.Sleep(10 * time.Second)
cancel()
time.Sleep(5 * time.Second)
fmt.Println("main stop")
}
type OtherContext struct {
context.Context
}
func work(ctx context.Context, name string) {
for {
select {
case <-ctx.Done():
fmt.Printf("%s get msg to cancel\n", name)
return
default:
fmt.Printf("%s is running \n", name)
time.Sleep(1 * time.Second)
}
}
}
func workWithValue(ctx context.Context, name string) {
for {
select {
case <-ctx.Done():
fmt.Printf("%s get msg to cancel\n", name)
return
default:
value := ctx.Value("key").(string)
fmt.Printf("%s is running value=%s \n", name, value)
time.Sleep(1 * time.Second)
}
}
}
这段代码中,都是一条链路下来的
根节点 context.Background() -> ctxa -> ctxb -> oc
其中ctxa加了个时间控制,所以到达一定的时间就会自动关闭
oc附带了个键对值