go语言并发编程

一、Goroutine

1.Goroutine概念

  1. Go中使用Goroutine来实现并发

  2. Goroutine是与其他函数或方法同时运行的函数或方法。

  3. Goroutine在线程上的优势

    • 与线程相比,Goroutine非常便宜。它们只是堆栈大小的几个kb,堆栈可以根据应用程序的需要增长和收缩,而在线程的情况下,堆栈大小必须指定并且是固定的。由于创建Goroutine的成本很小。因此,Go应⽤用程序可以并发运行数千个Goroutine。

    • 当使用Goroutine访问共享内存时,通过设计的通道可以防止竞态条件发生。通道可以被认为Goroutine通信的管道。

    Coroutine与Goroutine

    1. Coroutine协程

      • 协程,英文Coroutine,有称为微线程。是一种比线程更加轻量级的存在。正如一个进程可以拥有多个线程一样,一个线程也可以拥有多个协程。协程最初在1963年被提出。

      • 协程不是进程或线程,其执行过程更类似于子程序,或者说不带返回值的函数调用。最重要的是,协程不是被操作系统内核所管理,而完全是由程序所控制。这样带来的好处就是性能得到了很大的提升,不会像线程切换那样消耗资源Coroutine是编译器级的,Process和Thread是操作系统级的。

      • 协程的优势

        • 与传统的系统级线程和进程相比,协程的最大优势在于其轻量级,可以轻松创建上百万个,而不不会导致系统资源衰竭;线程和进程通常最多也不能超过一万个。这也是协程叫做轻量级线程的原因。

        • 协程的执行效率极⾼高。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销。和多线程比,线程数量越多,协程的性能优势就越明显。

    2. Coroutine与Goroutine比较:

      (1)、goroutine可能发生并行执行;但是coroutine始终顺序执行;

      • goroutine可能发生在多线程环境下,coroutine始终发生在单线程,coroutine程序需要主动交出控制权,宿主才能获得控制权并将控制权交给其他coroutine。

      • coroutine的运行机制属于协作式任务处理,应用程序在不需要使用CPU时,需要主动交出CPU使用权。如果开发者无意间让应用程序长时间占用CPU,操作系统也无能为力,计算机很容易失去响应或者死机。

      • goroutine属于抢占式任务处理,已经和现有的多线程和多进程任务处理非常类似。应用程序对CPU的控制最终需要有操作系统来管理,操作系统如何发现一个应用程序常时间占用CPU,那么用户有权终止这个任务。

      (2)、goroutine间使用channel通信;coroutine使用yield和resume操作。

2.Goroutine创建和使用

在函数或方法调用前面加上关键字go,将会同时运行一个新的Goroutine。

  • 使用go关键字创建Goroutine时,被调用的函数往往没有返回值,如果有返回值也会被忽略。

  • 如果需要在Goroutine中返回数据,必须使用通道channel,通过通道把数据从Goroutine中作为返回值传出。

    示例:

    //创建goroutine
    //此程序循环打印0-99之间的数字,打印出来是乱序的,为什么?因为这是多个goroutine,哪个先跑起来是不一定的
    func hello(i int){
        fmt.Println("hello",i)
    }
    //程序启动之后会创建一个主goroutine去执行
    func main(){
        for i:=0;i<100;i++{
            go hello(i)
            //go func(i int){   //用的是函数参数的那个i,不是外边的i
                //fmt.Println(i)
            //}(i)
        }
        fmt.Println("main")
        time.Sleep(time.Second)
        //main函数结束了,有main函数启动的goroutine也都结束了,所以需要加一个延迟
    }

    sync包中的waitGroup:如此创建goroutine的话,程序不知道goroutine什么时候执行完毕,延迟时间就会一直等待,导致输出出现卡顿并且浪费系统资源,可以通过WaitGroup来实现多个goroutine的同步,等待每个任务执行完成之后再退出:

    //WaitGroup
    var wg sync.WaitGroup//实现多个goroutine的同步,等待每个任务执行完成之后再退出
    func f(){
        rand.Seed(time.Now().UnixNano())//加随机数种子,每次执行时重新生成随机数
        for i:=0;i<5;i++{
            r1 := rand.Int()
            r2 := rand.Intn(10)//0<= x <10
            fmt.Println(r1,r2)
        }
    ​
    }
    ​
    func  f1(i int){
        defer wg.Done()//每执行完一个goroutine,减1
        time.Sleep(time.Millisecond * time.Duration(rand.Intn(300)))
        fmt.Println(i)
        //wg.Done()
    }
    ​
    func main(){
        //f()
        //wg.Add(10)
        for i:=0;i<10;i++{
            wg.Add(1)//每启动一个goroutine,加1
            go f1(i)
        }
        //如何知道这十个goroutine都结束了?
        //此时时间是随机的,不能简单使用time.Sleep()
        wg.Wait()//等待wg的计数器减为0
    }*/

    程序默认会跑满整个cpu,但是有时候不需要这么多资源,那么可以通过GOMAXPROCS来设置想使用的cpu数量。

    //GOMAXPROCESS
    var wg sync.WaitGroup
    func a(){
        defer wg.Done()
        for i:=0;i<10;i++{
            fmt.Printf("A:%d\n",i)
        }
    }
    ​
    func b(){
        defer wg.Done()
        for i:=0;i<10;i++{
            fmt.Printf("B:%d\n",i)
        }
    }
    ​
    func main(){
        //<1:不修改任何数值。
        //=1:单核心执行。
        //>1:多核并发执行。
        runtime.GOMAXPROCS(1)//指定想使用的cpu逻辑核心数,默认跑满整个cpu  8
        fmt.Println(runtime.NumCPU())//查询cpu核心数,此电脑为8核
        wg.Add(2)
        go a()
        go b()
        wg.Wait()
    }

    go关键字后也可以是匿名函数或闭包。

    func main() {
    go func() {
    var times int
    for {
    times++
    fmt.Println("tick" , times)
    time.Sleep(time.Second)
    }
    }()
    var input string
    fmt.Scanln(&input)
    }

二、channel

1.通道的概念

(一)、通道的概述

  1. 使用通道的意义

    • 单纯地将函数并发执行没有意义。函数与函数间需要交换数据才能体现出并发执行的意义。

    • 虽然可以使用共享内存进行数据交换,但是共享内存在不同goroutine中容易发生竞态问题,必须使用互斥对内存进行加锁,所以造成性能问题。

    • Go语言中提倡使用通道channel的⽅式代替共享内存。也就是说,Go语言中主张,应该通过数据传递来实现共享内存,⽽不是通过共享内存来实现消息传递。

    • 排队的目的是避免拥堵、插队造成的资源使用和交换过程低效问题。多个goroutine为了争抢数据,势必造成低效,使用队列的方式是最高效的,channel就是一种队列结构。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值