美文网首页Golang我爱编程go学习
golang基础介绍part-2(interface,gorou

golang基础介绍part-2(interface,gorou

作者: 太白菜Rennbon | 来源:发表于2018-06-03 13:38 被阅读178次

    Golang相关其他分享

    golang基础介绍part-1

    衔接介绍

    part-1中提到了Golang中各种关键字的基本用法和一些指针的注意事项,这张主要侧重go的一些相对比较高级的操作,如果对part-1的概念点还是一知半懂的话,这一章会比较困难,所以基础很重要,当然这章其实也是基础。

    推荐书籍

    《go in action》,《深入解析go》,《go源码剖析》,《go语言圣经》

    有的书可能老了,源码已经迭代了好几版了,需要自我鉴别,目前网上也有很多分析的例子

    本章概要

    戳一下看demo👈

    1. interface 实践 👈

    methed receivers values
    (t T) T and *T
    (t *T) *T

    如上图所示,如果使用指针接收者(*T)来实现一个接口,那么只有指向那个类型的指针(*T)才能够实现对应的接口。如果使用值接收者(T)来实现一个接口,那么那个类型的值和指针(T and *T)都能够实现对应的接口。

    在go中是没有继承的概念的,所以interface和组合对象这2个概念是很重要的,demo中也就该2点做了演示

    2. exception 异常与捕捉(try catch? panic defer recover) 👈

    package main
    import "log"
    func main() {
        log.Println("service start")
        //unforgivableSystemException()
        protect(unforgivableSystemException)
        log.Println("service stop")
    }
    func unforgivableSystemException() {
        panic("WTF!!!!")
    }
    func protect(g func()) {
        //执行完g()后执行
        defer func() {
            log.Println("done")
            //如果有panic的话会被recover到,相当于C#中的catch,阻止系统直接抛异常
            if err := recover(); err != nil {
                //为什么我这里没用fmt打印,而用log,你懂得,可以异常数据收集
                log.Printf("run time panic: %v", err)
            }
        }()
        //执行对应的函数
        g()
    }
    

    相对于C#,Java或其他语言中的exception而言,在go中有error和panic,日常C#开发中,我们会把人为能识别的异常通过标记一个枚举的errorCode返回,而正真的系统级异常则是exception。类似的,在golang中就大致相对着error和panic,error能更全面的控制各种人为识别的错误,在go中不推荐bool作为执行成功与否的返回值,因为bool不能完全解释false的原由到底是什么,只能表示逻辑通不过,所以error和errorCode相对应,而panic和exception相对应。

    3. goroutine and channel 👈

    goroutine运行机制

    图中,M是线程,P是处理器,G是goroutine,图左侧部分是M0线程上挂载了P对G队列进行处理,在执行G0时,当G0阻塞时,调度器会将M0线程与P隔离,并创建一个新的线程如图为M1来运行P上的其他G当,当阻塞在syscall上的G完成syscall调用后,G会去尝试获取一个可用的P,如果没有可用的P,那么G会被标记为runnable,之前的那个sleep的M将再次进入sleep,G在创建的时候相关执行参数会被拷贝到G的栈空间,这使得它和当前任务不再有任何关系,各自使用独立的栈空间,所以G相对于系统级多线程的上下文切换更轻量,效果更好。(这里的调度器是golang自己实现的调度器,非操作系统调度器)

    channel运行机制

    channel缓冲的概念如上图所示,原理上channel 其实就是一个队列加一个锁,channel中维护着队列中数据的个数,数据的大小,是否关闭状态,还配有轻量级的锁,源数据类型,收发数组的指针等等。

    4. data race 和 互斥锁 以及 原子函数 👈

    以下代码文件名:main.go

    package main
    import (
        "fmt"
        "sync"
        "sync/atomic"
    )
    var (
        num   int32
        num2  int32
        num3  int32
        wg    sync.WaitGroup
        mutex sync.Mutex //互斥锁
    )
    func main() {
        wg.Add(2)
        go Inc()
        go Inc()
        wg.Wait()
        fmt.Println(num, ":", num2, ":", num3)
    }
    func Inc() {
        defer wg.Done()
        for i := 0; i < 10000; i++ {
            //num3++
            /*原子函数,单纯效率比互斥锁高,
            但是原子锁由底层硬件支持,脱离的golang机制,
            虽然效率很好,但是会因为各种硬件的问题变的???(重要的字符要打3遍)
            所欲对于严格要求一致的地方不适合原子函数
            */
            atomic.AddInt32(&num, 1)
    
            mutex.Lock()
            { //这对花括号只是为了标记作用域,可以不写
                num2++
            }
            mutex.Unlock()
        }
    }
    

    data race 的出现会造成数据的不确定性,对于一个系统而言,这种不稳定因素是要极力避免的,以上的代码,我们通过“go run -race main.go” 出现以下的运行结果

    ==================
    WARNING: DATA RACE
    Read at 0x0000011d9e74 by goroutine 7:
      main.Inc()
          /Users/zhubin/go/src/demo/golang2/goroutine/go6/main.go:27 +0x79
    
    Previous write at 0x0000011d9e74 by goroutine 6:
      main.Inc()
          /Users/zhubin/go/src/demo/golang2/goroutine/go6/main.go:27 +0x96
    
    Goroutine 7 (running) created at:
      main.main()
          /Users/zhubin/go/src/demo/golang2/goroutine/go6/main.go:20 +0x88
    
    Goroutine 6 (running) created at:
      main.main()
          /Users/zhubin/go/src/demo/golang2/goroutine/go6/main.go:19 +0x70
    ==================
    20000 : 20000 : 13507
    Found 1 data race(s)
    exit status 66
    

    而当注释掉num3++后,运行结果将会是20000:20000:0,这里就不做细致的讲解了

    相关文章

      网友评论

        本文标题:golang基础介绍part-2(interface,gorou

        本文链接:https://www.haomeiwen.com/subject/cltfsftx.html