Golang基础_11-并发concurrency

Posted leafs99

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Golang基础_11-并发concurrency相关的知识,希望对你有一定的参考价值。

注意事项

  • goroutine只是官方的超级线程池
  • 高并发性:占用内存小,创建销毁很快
  • goroutine的简单易用,也在语言层面上给予开发者巨大的便利
  • 并发不是并行,并行是直接利用多核实现多线程的运行,并发是由切换时间片来实现“同时”运行
  • goroutine奉行通过通信(channel)来共享内存,而不是共享内存来通信

    channel

  • channel是goroutine沟通的桥梁,大都是阻塞同步的
  • 通过make创建,close关闭
  • channel是引用类型,也就是说,传入的参数可以直接对他本身操作

func main()
    c := make(chan bool)
    go func()
        fmt.Println("GO GO GO")
        c <- true
    ()
    <- c

/*
> Output:
command-line-arguments
GO GO GO
*/
  • 可以使用for range来迭代不断操作channel
  • 迭代的时候记得一定要在某个地方调用close(c)关闭,以避免造成死锁
func main()
    c := make(chan bool)
    go func()
        fmt.Println("GO GO GO")
        c <- true
        close(c)
    ()
    for v := range c 
    //程序运行到这,一直等待着c会有值
        fmt.Println(v)
    

  • 可以设置单向或者双向通道
  • 可以设置缓存大小,在未被填满前不会发生阻塞
    关于缓存,可参考:Go语言_并发篇
    技术图片
    有缓存是异步的,无缓存是同步阻塞的
    有缓存要先放
    无缓存要先取

    乱序及缺失问题..whatever

func main()
    runtime.GOMAXPROCS(runtime.NumCPU())
    c := make(chan bool)
    for i:=0; i<10 ; i++ 
        go Go(c,i)
    
    <-c

func Go(c chan bool, index int)
    a := 1
    for i:=0;i<1000000;i++
        a += i
    
    fmt.Println(index,a)

    if index==9 
        c <- true
    

/*
> Output:
command-line-arguments
1 499999500001
0 499999500001
2 499999500001
9 499999500001
*/

以上输出十分不符合圣意,大臣们献出以下两个计策

计策一:给channel加buffer

func main()
    runtime.GOMAXPROCS(runtime.NumCPU())
    c := make(chan bool,10)
    for i:=0; i<10; i++ 
        go Go(c,i)
    
    for i:=0;i<10;i++
        <- c
    

func Go(c chan bool, index int)
    a := 1
    for i:=0;i<1000000;i++
        a += i
    
    fmt.Println(index,a)

    c <- true

/*
> Output:
command-line-arguments
2 499999500001
1 499999500001
9 499999500001
0 499999500001
6 499999500001
3 499999500001
5 499999500001
7 499999500001
8 499999500001
4 499999500001
*/

计策二:引入sync包

package main
import (
    "fmt"
    "runtime"
    "sync"
)
func main()
    //(runtime包是goroutine的调度器),runtime.GOMAXPROCE设置允许同时最多使用多少个核
    runtime.GOMAXPROCS(runtime.NumCPU())
    wg := sync.WaitGroup
    for i:=0; i<10; i++ 
        //waitgroup作为结构,使用&进行地址传递
        go Go(&wg,i)
    
    wg.Wait()

func Go(wg *sync.WaitGroup, index int)
    a := 1
    for i:=0;i<1000000;i++
        a += i
    
    fmt.Println(index,a)

    wg.Done()

select

  • 专门为了channel设计的结构
func main()
    c1,c2 := make(chan int),make(chan string)
    o := make(chan bool)
    go func()
        for
            select
            case v,ok := <-c1:
                if !ok
                    o <- true
                    break
                
                fmt.Println("c1",v)
            case v,ok := <-c2:
                if !ok
                    o <- true
                    break
                
                fmt.Println("c2",v)
            
        
    ()
    c1 <- 1
    c2 <- "hi"
    c1 <- 3
    c2 <- "lel"

    close(c1)
    //close(c2)
    for i:=0;i<2;i++
        <- o
    

//没办法同时记录两个select的执行次数
  • 可以处理一个或者多个channel的发送与接收
func main()
    c := make(chan int)
    go func()
        i := 0
        for v:= range c 
            i ++
            fmt.Println(v)
            if i>10
                break
            
        
    ()

    for 
        select 
        case c <- 0:
        case c <- 1:
        
    

//运行结果很鬼畜,,
  • 同时有多个可用的channel时按随机顺序处理
  • 可用空的select来阻塞main函数
  • 可设置超时
package main
import (
    "fmt"
    "time"
)
func main()
    c := make(chan bool)
    select 
    case v := <- c:
        fmt.Println(v)
    case <-time.After(3*time.Second):
        fmt.Println("timeout")
    

//time.After()返回一个time型的chan

例子:用goroutine实现发送接收数条消息

package main

import (
    "fmt"
)

var cc chan string

func main() 
    cc = make(chan string)

    go Go()
    for i := 0; i < 5; i++ 
        cc <- fmt.Sprintf("From main:hello, #%d", i)
        fmt.Println(<-cc)
    


func Go() 
    for i := 0; ; i++ 
        fmt.Println("djd", <-cc)
        cc <- fmt.Sprintf("From Go:hi,#%d", i)
    

/*
    djd From main:hello, #0
    From Go:hi,#0
    djd From main:hello, #1
    From Go:hi,#1
    djd From main:hello, #2
    From Go:hi,#2
    djd From main:hello, #3
    From Go:hi,#3
    djd From main:hello, #4
    From Go:hi,#4
*/

以上是关于Golang基础_11-并发concurrency的主要内容,如果未能解决你的问题,请参考以下文章

MySQL基础--11---并发线程参数 innodb_thread_concurrency

MySQL基础--11---并发线程参数 innodb_thread_concurrency

GOLANG如何并发

GO语言基础之并发concurrency

线程模型的综述

golang中map并发读写问题及解决方法