zoukankan      html  css  js  c++  java
  • golang核心Goroutine和channel

    一、Goroutine

    1、介绍

    goroutine简介 goroutine是go语言中最为NB的设计,也是其魅力所在,goroutine的本质是协程,是实现并行计算的核心。goroutine使用方式非常的简单,只需使用go关键字即可启动一个协程,并且它是处于异步方式运行,你不需要等它运行完成以后在执行以后的代码。

    1、 主线程是一个物理线程,直接作用在 cpu 上的。是重量级的,非常耗费 cpu 资源。

    2、 协程从主线程开启的,是轻量级的线程,是逻辑态。对资源消耗相对小。

    3、 Golang 的协程机制是重要的特点,可以轻松的开启上万个协程。其它编程语言的并发机制是一般基于线程的,开启过多的线程,资源耗费大,这里就突显 Golang 在并发上的优

    4、goroutine通过go关键字实现了,其实就是一个普通的函数。

    为了充分了利用多 cpu 的优势,在 Golang 程序中,设置运行的 cpu 数目(Go1.8以后默认运行在多核上)

    num := runtime.NumCPU()    //本地机器的逻辑CPU个数
    runtime.GOMAXPROCS(num)    //设置可同时执行的最大CPU数,并返回先前的设置
    fmt.Println(num)
    

      

    2、执行流程图

    3、简单例子

    package main
    import (
        "fmt"
        "time"
    )
    
    func test(){
        for i := 1;i <= 10;i++ {
            fmt.Println(i)
            time.Sleep(time.Second * 2 ) //睡眠2s        
        }
    
    }
    
    func main(){
        go test() //开启协程
        for i := 1;i <= 10;i++ {
            fmt.Println("===============")
            time.Sleep(time.Second  ) //睡眠1s        
            
        }
    }
    
    
    #########结果######
    ===============
    1
    ===============
    ===============
    2
    ===============
    3
    ===============
    ===============
    4
    ===============
    ===============
    5
    ===============
    ===============
    6
    

      

    4、使用全局变量加锁的例子

    计算0-10的乘阶

     代码:

    package main
    
    import (
        "fmt"
        "sync"
        "time"
    )
    
    var (
        m    = make(map[int]uint64)
        //lock是一个全局互斥锁
        //sync.Mutex 是互斥锁
        lock sync.Mutex //申明一个互斥锁
    )
    
    type task struct {
        n int
    }
    
    func calc(t *task) {
        defer func() {
            err := recover()
            if err != nil {
                fmt.Println("error...")
                return
            }
        }()
    
        var sum uint64
        sum = 1
        for i := 1; i < t.n; i++ {
            sum *= uint64(i)
        }
    
        lock.Lock() //加锁
        m[t.n] = sum
        lock.Unlock() //解锁
    }
    
    func main() {
        for i := 0; i <= 10; i++ {
            t := &task{n: i}
            go calc(t) // Goroutine来执行任务
        }
    
        time.Sleep(time.Second) // Goroutine异步,所以等一秒到任务完成
    
        lock.Lock() //读全局数据加锁
        for k, v := range m {
            fmt.Printf("%d! = %v
    ", k, v)
        }
        fmt.Println(len(m))
        lock.Unlock() //解锁
    }
    
    
    #########结果#######
    10! = 362880
    0! = 1
    2! = 1
    3! = 2
    4! = 6
    5! = 24
    7! = 720
    8! = 5040
    1! = 1
    6! = 120
    9! = 40320
    11
    

      

    二、channel 

    channel 的基本介绍

    1、channle 本质就是一个数据结构-队列

    2、数据是先进先出

    3、线程安全,多 goroutine 访问时,不需要加锁,就是说 channel 本身就是线程安全的

    4、channel 有类型的,一个 string 的 channel 只能存放 string 类型数

    示意图:

    文档参考:

    http://www.cnblogs.com/wdliu/p/9272220.html

    channel 使用的注意事项

    1、channel 中只能存放指定的数据类型

    2、channle 的数据放满后,就不能再放入了

    3、如果从 channel 取出数据后,可以继续放入

    4、在没有使用协程的情况下,如果 channel 数据取完了,再取,就会报 dead lock

  • 相关阅读:
    GIT学习笔记(2):时光机穿梭与远程仓库
    CNN学习笔记:正则化缓解过拟合
    Java分布式:RPC(远程过程调用)
    设计模式:学习笔记(12)——代理模式
    算法:乐观锁与悲观锁
    Python:笔记(5)——错误、调试和测试
    算法:LRU(最近最少使用)
    Python:笔记(4)——高级特性
    方法论:带着问题找答案
    Cache-Aside模式
  • 原文地址:https://www.cnblogs.com/zhangb8042/p/10577006.html
Copyright © 2011-2022 走看看