[置顶] Golang学习摘录(二)

Golang学习二

  1. Full slice expressions切片操作

    • Python a[low: high: direction]

      比如 a = [1, 2, 3], a[1:2:-1]负1表示反方向,结果是[3,2]

    • Golang第三个不是表示方向:a[low : high : max],string类型切片不支持max操作。

      max参数用来指定返回的切片的容量,slice在golang里底层是数组,并且有默认初始大小cap(a)。指定max参数后,返回的slice底层数组将不再是默认大小,而是max-low大小.

      所以有如下约定: 0 <= low <= high <= max <= cap(a)

      a := [5]int{1, 2, 3, 4, 5}

      t := a[1:3:9]

      此时切片t类型是[]int,长度length是2,容量是9-1等于8.意思是说,t底层数组长度为8,后续对t做append操作,只要大小不超过8,不必重新分配地址。

  2. Type assertions

    go的类型判断有点特别,v, ok := x.(T)断言x不是nil并且x类型是T。如果类型判断正确,ok为true,v为x转化为T后的值。如果失败,ok为false,v是T类型的zero_value.

  3. 协程入门

    如果有Python功底,对协程coroutine很熟悉,理解goroutine分分钟的事。goroutine与coroutine两个单词长这么像,就是因为本来就一回事。不理解也没事,先看看协程。

    greenlet:python协程基础框架,很原始,是纯手工的协程框架

    • from greenlet import greenlet
      def test1():
          print 12
          gr2.switch()
          print 34
      def test2():
          print 56
          gr1.switch()
          print 78
      gr1 = greenlet(test1)
      gr2 = greenlet(test2)#创建两个协程test1,test2,但并未启动
      gr1.switch()#切换到gr1,即启动协程gr1
      

    创建两个协程(greenlet框架叫做greenlet),分别是test1,test2,但是并未启动两个协程。然后主协程执行gr1.switch(),CPU执行权交给协程test1,输出12,然后切换到协程test2输出56,然后CPU执行权又切回test1,输出34。由于此时并没有切换到test2,78不会被输出,程序结束。

    上面就是协程入门,可以看到greenlet所有切换工作必须由代码显示执行,框架不会自动调度,所以说greenlet是纯手工的框架。协程跟多线程有个最大区别:某个协程如果不通过switch交出CPU使用权,其他协程无法获得CPU。在一个线程内部,包含着很多协程,当该线程获得CPU时,该线程内的switch进来(获得CPU)但是还没有switch出去(交出CPU)的协程获得CPU,其他协程只能等待它switch交出CPU使用权。

    gevent是比greenlet高级的协程框架,前面说了,greenlet的协程切换时纯手工,原始,那么gevent就是高级的:gevent会自动创建一个主协程,级别比较高,我们叫做调度器,它会自动调度该线程内的很多其他协程,当某个协程阻塞住,强行要回CPU使用权,给其他没有阻塞住的协程使用,如果所有其他的协程都阻塞,它就自个拿着CPU使用权,轮询其他协程,看谁不阻塞了,再交给谁。gevent能让程序员像写多线程一样写多协程,切换,调度,框架都做好了,并且接口与多线程类似,学习难度低。

  4. goroutine

    前面说了协程,golang的goroutine库就是更高级的gevent,也是自动调度,想要goroutine同步就要使用channel或者其他互斥元,与多线程编程十分类似。

    unbuffered channel可以用来同步goroutine

    buffered channel可以用作counting semaphore,可以参考上一篇golang学习文章里的信号量限流的例子

    sync包里提供了sync.Mutex or sync.RWMutex两种互斥元。说直白点就是锁,获取锁,释放锁从而同步

    sync.Once用来保证一堆goroutine执行同一个函数,只会执行一次,其他的阻塞直到那一次执行结束

    var a string
    var once sync.Once
    func setup() {
        a = "hello, world"
    }
    func doprint() {
        once.Do(setup)
        print(a)
    }
    func threeprint() {
        go doprint()
        go doprint()
        go doprint()
    }
    

    虽然起了3个goroutine去执行setup,但是once.Do保证只会有一个goroutine执行一次setup,其他goroutine等待它setup结束,然后打印3次。

你可能感兴趣的:(golang)