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

  • 相关阅读:
    122. Best Time to Buy and Sell Stock II
    121. Best Time to Buy and Sell Stock
    72. Edit Distance
    583. Delete Operation for Two Strings
    582. Kill Process
    indexDB基本用法
    浏览器的渲染原理
    js实现txt/excel文件下载
    git 常用命令
    nginx进入 配置目录时
  • 原文地址:https://www.cnblogs.com/zhangb8042/p/10577006.html
Copyright © 2011-2022 走看看