• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    详解go语言的并发

    1、启动go语言的协程

    package main
     
    import (
        "fmt"
        "runtime"
    )
     
    //runtime包
     
    func main() {
        //runtime.Gosched() 用于让出cpu时间片,让出这段cpu的时间片,让调度器重新分配资源
     
        //写一个匿名函数
        s := "test"
        go func(s string) {
            for i :=0;i 2;i++ {
                fmt.Println(s)
            }
        }(s)
     
        for i :=0;i 2;i ++ {
            //如果代码跑到这里,调度器会把cpu资源释放出来,让调度器重新分配cpu资源,可以分配到子协程,也可以重新分配到主协程
            runtime.Gosched()
            fmt.Println("123")
        }
    }

    2、runtime.Goexit()方法。立即终止当前的协程

    package main
     
    import (
        "fmt"
        "runtime"
        "time"
    )
     
    //runtime.Goexit()   立即终止当前的协程
    func main() {
        go func() {
            defer fmt.Println("A.defter")
            func () {
                defer fmt.Println("B.defter")
                //立即终止当前的协程,函数会走defer流程
                runtime.Goexit()
                fmt.Println("B")
            }()
            fmt.Println("A")
        }()
        for {
            time.Sleep(2 * time.Second)
        }
    }
     
    //不加runtime.Goexit()的结果
    //B
    //B.defter
    //A
    //A.defter
     
    //加runtime.Goexit()的结果
    //B.defter
    //A.defter

    3、runtime.GOMAXPROCS()表示go使用几个cpu执行代码

    package main
     
    import (
        "fmt"
        "runtime"
    )
     
    func main() {
        //runtime.GOMAXPROCS() 表示让go用几个cpu做后面的事情
        n := runtime.GOMAXPROCS(4)
        fmt.Printf("%T--->%p---%d\n",n,n,n)
        for {
            go fmt.Print("0")
            fmt.Print(1)
        }
    }

    4、管道定义和创建管道

    package main
     
    import "fmt"
     
    //go语言的协程运行在相同的地址空间,因此访问共享内存必须做好同步,处理好线程安全问题
     
    //go语言的协程之间的通信通过协程间通信来共享内存,而不是共享内存来通信
     
    //channel是一个引用类型,用于多个协程间通信,内部实现了同步,确保并发安全
     
     
    //通道一般是结合协程一起使用
     
     
    //如果通道中没有数据,后面你还去取数据,则会报错
    //fatal error: all goroutines are asleep - deadlock!
    func main() {
        //test45_1 := make(chan int) //定义一个无缓冲的通道
     
        //无缓冲的通道是值在接受数据前没有任何能力保存数据,只能有一个数据进入通道,进入通道后,该通道就会加锁,一直到这个数据被取出,锁才释放
     
        //无缓冲的通道有可能阻塞,如果我发送一个数据到通道,但是没有协程来取数据,则对于第一个协程就被阻塞
     
        //test45_2 := make(chan int,10)  //定义 一个有缓冲的通道
     
     
        //有缓冲的通道就是通道可以存储指定数量的数据,数据在里面也是有顺序的,但是如果缓冲的数量满了,这个通道也会是阻塞的
     
        //
        //test45_1 - 10   //发送数据到通道
        //- test45_1      //接受通道中的数据,并丢弃
        //x := -test45_1 //从通道取值并赋值给x
        //x,ok := -test45_1  //ok检查通道是否关闭或者是否为空
     
     
        //1、创建一个存放int类型的通道
        test45_1 := make(chan int)
     
        go func() {
            defer fmt.Println("子协程结束")
            fmt.Println("子协程正在运行")
     
            test45_1 - 111
        }()
        //- test45_1
        //主协程从通道中取数据
        x := - test45_1
        fmt.Println(x)
        fmt.Println("主协程结束")
    }

    5、管道的缓冲

    package main
     
    import (
        "fmt"
        "time"
    )
     
    func main() {
        //无缓冲的通道,长度为0就可以了,有缓冲的通道,这里设置为非0就可以了
        test46_1 := make(chan int,0)
     
        //%P是打印内存地址,%T是打印变量的类型
        //fmt.Printf("长度:%d--->容量:%d---->%P----%T",len(test46_1),cap(test46_1),test46_1,test46_1)
     
        go func() {
            defer fmt.Printf("子协程结束")
     
            for i :=0;i  3;i ++ {
                fmt.Println("子协程插入数据")
                test46_1 - i
                //fmt.Printf("长度:%d--->容量:%d---->%P----%T",len(test46_1),cap(test46_1),test46_1,test46_1)
     
            }
     
        }()
     
        time.Sleep(2 * time.Second)
        for j :=0;j 3;j++ {
            fmt.Println("主协程取数据")
            num := - test46_1
            fmt.Println(num)
        }
    }

    6、关闭管道和接受关闭管道的信号

    package main
     
    import "fmt"
     
    //close()方法,关闭通道的意思
     
    func main() {
        test47_1 := make(chan int,4)
     
        go func() {
            for i :=0;i  10;i ++ {
                test47_1 - i
            }
            //这个的意思关闭通道test47_1
            close(test47_1)
        }()
     
        //for的写法,遍历通道
        //for {
        //  //子协程关闭了通道,这里ok就可以接收到,这里就可以走到bread流程,ok这个参数表示通道是否关闭
        //  if data,ok := - test47_1;ok {
        //      fmt.Println(data)
        //  }else {
        //      break
        //  }
        //}
     
        //range的写法,遍历通道
        for data := range test47_1 {
            fmt.Println(data)
        }
        fmt.Println("主协程结束")
    }

    7、只读管道和只写管道和生产者和消费者模型

    package main
     
    import (
        "fmt"
        "time"
    )
     
    //默认情况下,管道是双向的,既可以写入数据,也可以读出数据。go也可以定义单方向的管道,也就是说只发送数据,或者只写入数据
     
    //可以把双向的管道转换为单向的管道,但是不能把单向的管道转换为双向的管道
     
    //单方向的管道
     
    func producter(out chan - int)  {
        defer close(out)
        for i := 0;i  10;i++ {
            out - i
        }
     
    }
     
    func consumer(int -chan int){
        for num := range int {
            fmt.Println(num)
        }
    }
    func main() {
     
        //1、定义管道
        //定义一个正常的管道
        //var test48_1 chan int
     
        //定义一个单向的只写的管道
        //var test48_2 chan - float32
     
        //定义一个单向的只读的管道
        //var test48_3 - chan int
     
        //2、转换管道
     
        //转换正常管道为只写或者只读的管道
        //定义一个正常的管道
        //test48_4 := make(chan int,3)
     
        //把一个正常的管道转换为一个只写的管道
        //var write_only chan - int = test48_4
     
        //把一个正常的管道转换为一个只读的管道
        //var read_only - chan int = test48_4
     
     
     
        test48_5 := make(chan int,4)
     
        //启动生产者
        go producter(test48_5)
     
        //启动消费者
        consumer(test48_5)
     
        time.Sleep(10 * time.Millisecond)
        fmt.Println("down")
     
    }

    8、Timer定时器

    package main
     
    import (
        "fmt"
        "time"
    )
     
    //定时器
     
    //time.NewTimer()。时间到了,只执行一次
    //time.NewTicker(),周期性的执行
     
    func main() {
        //1、创建一个定时器,2s后定时器会将一个时间保存到一个C
        test49_1 := time.NewTimer(2 * time.Second)
     
        //打印系统当前的时间
     
        t1 := time.Now()
     
        fmt.Printf("t1----->%v\n",t1)
     
        //从管道中取出C打印
     
        t2 := - test49_1.C
        fmt.Printf("t2----->%v\n",t2)
     
     
     
        //2、证明timer只执行一次
        //test49_2 := time.NewTimer(4 * time.Second)
        //
        //for {
        //  c := - test49_2.C
        //  fmt.Println(c)
        //}
     
        //3、通过timer实现一个延时的功能
     
        //方式1
        //time.Sleep(2 * time.Second)
     
        //方式2
        //test49_3 := time.NewTimer(2 * time.Second)
     
        //方式3
     
        //-time.After(2 *time.Second)
     
        //4、停止定时器
        test49_4 := time.NewTimer(4 * time.Second)
        //子协程
        go func() {
            //这个意思是3s后才能取出来数据
            - test49_4.C
     
            fmt.Println("定时器时间到了")
        }()
     
        //关闭定时器
        stop := test49_4.Stop()
        if stop {
            fmt.Println("定时器已经关闭")
        }
     
        //5、重置定时器
        test49_5 := time.NewTimer(4 * time.Second)
        //重置定时器为1s
        test49_5.Reset(1 * time.Second)
     
        for {
     
        }
        }

    9、ticker定时器和关闭ticker定时器

    package main
     
    import (
        "fmt"
        "time"
    )
     
    //time.NewTicker(),定时器,响应多次
     
    func main() {
        //创建一个定时器,间隔1s
        test50_1 := time.NewTicker(time.Second)
        i := 0
        go func() {
            for {
                c := - test50_1.C
                fmt.Println(c)
                i ++
                fmt.Println(i)
            }
            }()
     
     
        for {
     
        }
    }

    10、select语句

    package main
     
    import (
        "fmt"
    )
     
    //go语言提供select关键字,用来监听通道上的数据流动,语法和switch类似,区别是select必须要求每个case语句里必须是一个IO操作
     
    //如果都能匹配到,则随机选择一个通道去跑,select是比较随便的
     
    func main() {
        //test51_1 := make(chan int,3)
        //select {
        //case - test51_1:
        //  fmt.Println("jja")
        ////如果从通道中可以读出数据,则执行这里
        //case test51_1 - 1:
        //  fmt.Println("aa")
        ////如果通道中北写入数据,则执行号这里
        //default:
        //  fmt.Println("hah")
        ////如果上面都没成功,则执行这里
        //}
     
     
        test51_1 := make(chan int,1)
        test51_2 := make(chan string,1)
     
        go func() {
            //time.Sleep(2 * time.Second)
            test51_1 - 1
     
        }()
        go func() {
            test51_2 - "Hello World"
        }()
     
        select {
        case Value1:= - test51_1:
            fmt.Println(Value1)
        case Value2 := - test51_2:
            fmt.Println(Value2)
        }
        fmt.Println("结束")
     
    }

    11、协程同步锁

    package main
     
    import (
        "fmt"
        "sync"
        "time"
    )
     
    //go语言的协程同步锁,解决并发安全问题
     
     
    //取钱的例子
     
    type Account struct {
        money int
        flag sync.Mutex
    }
     
    func Check(a *Account)  {
        time.Sleep(1 * time.Second)
    }
     
    func (a *Account)SetAccount(n int)  {
        a.money = n
    }
     
    func (a *Account)GetAccount() (n int) {
        return a.money
    }
     
    func (a *Account) buy1(n int)  {
        a.flag.Lock()
        if a.money > n {
            Check(a)
            a.money -= n
        }
        a.flag.Unlock()
        fmt.Println(a.money)
    }
     
     
    func (a *Account) buy2(n int)  {
        a.flag.Lock()
        if a.money > n {
            Check(a)
            a.money -= n
        }
        a.flag.Unlock()
        fmt.Println(a.money)
    }
     
    func main() {
        var test52_1 Account
        test52_1.SetAccount(10)
     
        go test52_1.buy1(5)
        go test52_1.buy2(6)
        for {
     
        }
    }

    12、wait

    我们自己实现wait

    package main
     
    import "fmt"
    //Add() 计数加1
    //Done() 计数减1
    //Wait() 主函数调用
    func main() {
        test53_1 := make(chan int,2)
        count := 2
        go func() {
            fmt.Println("子协程1")
            test53_1 - 1
        }()
        go func() {
            fmt.Println("子协程2")
            test53_1 - 2
        }()
     
        for range test53_1 {
            count --
            if count == 0 {
                fmt.Println("所有的子协程都已经结束")
                close(test53_1)
            }
        }
    }

    go语言为我们实现wait

    package main
     
    import (
        "fmt"
        "sync"
    )
    //Add() 计数加1
    //Done() 计数减1
    //Wait() 主函数调用
    func main() {
     
        var wait_group sync.WaitGroup
     
        //这里就是子协程的个数
        wait_group.Add(2)
        //test54_1 := make(chan int,2)
     
        go func() {
            fmt.Println("子协程1")
            wait_group.Done()
        }()
        go func() {
            fmt.Println("子协程2")
            wait_group.Done()
        }()
     
     
        wait_group.Wait()
        //close(test53_1)
        fmt.Println("所有的子协程都结束")
     
    }

    以上就是详解go语言的并发的详细内容,更多关于go语言的并发的资料请关注脚本之家其它相关文章!

    您可能感兴趣的文章:
    • 快速解决Golang Map 并发读写安全的问题
    • 浅谈golang并发操作变量安全的问题
    • golang高并发限流操作 ping / telnet
    • golang gin 框架 异步同步 goroutine 并发操作
    • Golang 实现分片读取http超大文件流和并发控制
    • golang-gin-mgo高并发服务器搭建教程
    • 详解Go多协程并发环境下的错误处理
    • Django高并发负载均衡实现原理详解
    • golang通过context控制并发的应用场景实现
    • 一百行Golang代码实现简单并发聊天室
    • 基于Django的乐观锁与悲观锁解决订单并发问题详解
    上一篇:详解Go语言变量作用域
    下一篇:Go 代码生成工具详解
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯 版权所有

    《增值电信业务经营许可证》 苏ICP备15040257号-8

    详解go语言的并发 详解,语言,的,并发,详解,