zoukankan      html  css  js  c++  java
  • Goroutine和Panic

    一. Goroutine

    Goroutine是Golang2个核心的设计之一,Goroutine在Golang里面指的是协程。我们知道线程属于系统层面,通常来说创建一个新的线程会消耗较多的资源且管理不易。而Goroutine就像轻量级的线程,但我们称其为协程,一个Go程序可以运行超过数万个Goroutine,并且这些性能都是原生级的,随时都能够关闭、结束。

    在内置的官方包中也不时能够看见Goroutine的应用,像是net/http中用来监听网络服务的函数实际上是创建一个不断运行循环的Goroutine。

    我们可以通过runtime.GOMAXPROCS来设置同时执行的最大CPU数,GO默认是使用一个CPU核的,除非设置runtime.GOMAXPROCS
    那么在多核环境下什么情况下设置runtime.GOMAXPROCS会比较好的提高速度呢?适合于CPU密集型、并行度比较高的情景。如果是IO密集型,CPU之间的切换也会带来性能的损失。

    func main() {
        num := runtime.NumCPU()    # 本地机器的逻辑CPU个数
        runtime.GOMAXPROCS(num)    # 设置可同时执行的最大CPU数
        fmt.Println(num)
    }
     

    二. 并发

    Goroutine最大的一个功能就是实现高并发,通过Goroutine能够让程序以异步的方式运行,而不需要担心一个函数导致程序中断,因此Go语言也非常地适合网络服务。

    我们通过go让其中一个函数异步运行,如此就不需要等待该函数运行完后才能运行下一个函数。

    func main() {
        # 通过 `go` 我们可以把这个函数异步执行,这样就不会阻塞往下执行。
        go loop()
        # 执行 Other
    }


    三. Recover

    虽然Goroutine能够实现高并发,但是如果某个Goroutine panic了,而且这个Goroutine里面没有捕获recover,那么整个进程就会挂掉。所以,好的习惯是每当go产生一个goroutine,就需要写下recover。

    func domainPut(num int) {
        defer func() {
            err := recover()
            if err != nil {
                fmt.Println("panic error.")
            }
        }()
        panic("error....")
    }

    func main() {
        for i := 0; i < 10; i++ {
            domainName := i
            go domainPut(domainName)
        }
        time.Sleep(time.Second * 2)
    }

    四. 规范

    使用Goroutine实现高并发有一些规范开发必须要注意,否则很容易带来困扰
    1. Golang主程序必须要等待所有的Goroutine结束才能够退出,否则如果先退出主程序会导致所有的Goroutine可能未执行结束就退出了

    package main

    import (
        "sync"
        "fmt"
        "time"
    )

    func calc(w *sync.WaitGroup, i int)  {
        defer func() {
            err := recover()
            if err != nil {
              fmt.Println("panic error.")
            }
        }()
        
        fmt.Println("calc: ", i)
        time.Sleep(time.Second)
        w.Done()
    }

    func main()  {
        # WaitGroup能够一直等到所有的goroutine执行完成,并且阻塞主线程的执行,直到所有的goroutine执行完成。
        wg := sync.WaitGroup{}    
        for i:=0; i<10; i++ {
            wg.Add(1)
            go calc(&wg, i)
        }
        # 阻塞主线程等到所有的goroutine执行完成
        wg.Wait()
        fmt.Println("all goroutine finish")
    }


    2. 每个Goroutine都要有recover机制,因为当一个Goroutine抛panic的时候只有自身能够捕捉到其它Goroutine是没有办法捕捉的。如果没有recover机制,整个进程会crash。
    3. recover只能在defer里面生效,如果不是在defer里调用,会直接返回nil。
    4. Goroutine发生panic时,只会调用自身的defer,所以即便主Goroutine里写了recover逻辑,也无法recover。

    # Goroutine里面需要写defer recover机制
    go func() {
       defer func() {
          err := recover()
          if err != nil {
             fmt.Println("panic error.")
          }
       }()
       # other code
    }()
    ————————————————
    原文链接:https://blog.csdn.net/chenguolinblog/article/details/90665080

  • 相关阅读:
    JSP动作--JSP有三种凝视方式
    osgi实战学习之路:5.生命周期及利用命令、装饰者模式实现基于socket交互Bundle命令demo
    一个int类型究竟占多少个字节
    FORM验证简单demo
    centOS设为文本启动方式
    定时关机命令——shutdown
    【剑指offer】Q38:数字在数组中出现的次数
    Union和Union All的差别
    基于协同过滤的推荐引擎
    Java实现 蓝桥杯VIP 算法提高 企业奖金发放
  • 原文地址:https://www.cnblogs.com/ithubb/p/14636238.html
Copyright © 2011-2022 走看看