golang 代码笔记

互斥锁,g0获取锁,到释放锁之间,g1去获取锁失败,阻塞,g0释放锁之后g1获取锁成功,gn阻塞。

package main

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

func main() {
    //声明
    var mutex sync.Mutex
    fmt.Println("Lock the lock. (G0)")
    //加锁mutex
    mutex.Lock()

    fmt.Println("The lock is locked.(G0)")
    for i := 1; i < 4; i++ {
        go func(i int) {
            fmt.Printf("Lock the lock. (G%d)
", i)
            mutex.Lock()
            fmt.Printf("The lock is locked. (G%d)
", i)
        }(i)
    }
    //休息一会,等待打印结果
    time.Sleep(time.Second)
    fmt.Println("Unlock the lock. (G0)")
    //解锁mutex
    mutex.Unlock()

    fmt.Println("The lock is unlocked. (G0)")
    //休息一会,等待打印结果
    time.Sleep(time.Second)
}

原子操作

通过atomic的AddUint32方法,只有一个协程可以操作sum,保证结果一定是150,原子操作相当于给sum加了锁。

package main

import (
    "fmt"
    "sync"
     "sync/atomic"
)

var m *sync.Mutex

func main() {
    var sum uint32 = 100
    var wg sync.WaitGroup
    for i := 0; i < 50; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            //sum += 1 //1
            atomic.AddUint32(&sum, 1) //2
        }()
    }
    wg.Wait()
    fmt.Println(sum)
}

go的“any”类型

类似ts的any,但是很麻烦的是用这个字段的时候需要强转,就是.([]string)这个操作,如果range的时候没把内容转成字符串,就会报错,因为毕竟他是interface{}类型

package main

import (
    "fmt"
)

func main() {
    m := map[string]interface{}{
        "Name": "Wednesday",
        "Age":  6,
        "Parents": []string{
            "Gomez",
            "Morticia",
        },
    }

    maps := []interface{}{
        "Gomez",
        "Morticia",
    }
    fmt.Println(maps, m)
    for key, value := range m["Parents"].([]string) {
        fmt.Println("Key:", key, "Value:", value)
    }
}

channel

go的chan关键字可以创建一个channel用于协程通信, ch <- 是写数据,<- ch是读数据,你也可以用range来读数据,当读不到数据的时候就会阻塞。所以下面的代码不写sleep,go进程也不会退出。

import (
    "fmt"
    //  "time"
)

func main() {
    var ch = make(chan []int)
    num := []int{1, 2, 3}
    i := 0
    go func() {
        for {
            ch <- num
            num = append(num, i)
            i++
            fmt.Println("write")
        }
    }()
    for nu := range ch {
        fmt.Println(nu)
    }

}

channel一般都用select来消费,只要一个case成功就完成,不然就阻塞到成功。

package main

import (
    "time"
    "fmt"
)

func main(){
    c := make(chan int)
    select{
    case <- c:
        fmt.Println("没有数据")
    case <-time.After(5* time.Second):
        fmt.Println("超时退出")
    }
}

利用多核cpu

通过设置runtime.GOMAXPROCS(2),让go协程可以跑在两个cpu上,所以打印的2次0-100,没有先后顺序。go的多核利用是利用多个cpu上跑协程。
并不是多核一定高效,比如io操作,单核比多核更快,单核没有线程切换的损耗,而且io操作并不需要go来做啥。多核的场景应该是高计算的任务。


import (
    "fmt"
    "runtime"
)

var quit chan int = make(chan int)

func loop() {
    for i := 0; i < 100; i++ { //为了观察,跑多些
        fmt.Printf("%d ", i)
    }
    quit <- 0
}

func main() {
    runtime.GOMAXPROCS(2) // 最多使用2个核

    go loop()
    go loop()

    for i := 0; i < 2; i++ {
        <-quit
    }
}
原文地址:https://www.cnblogs.com/dh-dh/p/9219876.html