【Golang学习笔记】05

要点

  • goroutine
  • runtime.GOMAXPPROCS
  • Channel select
  • sync.mutex
  • init

多线程

  • goroutine
    go + func
func task01()  {
    for ;; {
        fmt.Println("task01")
    }
}

func task02()  {
    for ;; {
        fmt.Println("task02")
    }
}


func main() {
    go task01()
    go task02()
    time.Sleep(1 * time.Minute)
}
/*
task1和task2并发执行
……
task01
task01
task02
task01
task02
task01
task01
……
*/
  • goroutine的匿名写法
    //匿名goroutine
    go func() {
        fmt.Printf("\n Task3Start TimeNow: ",time.Now())
        time.Sleep(2 * time.Second)
        fmt.Printf("\n Task3End TimeNow: ",time.Now())
    }()
  • sync.WaitGroup
    阻塞线程,可以阻塞住主线程使其等待子线程结束
    wg.Add(1),wg.Done(wg.Add(-1)),wg.Wait()当wg不为0时阻塞住线程
func task1()  {
    fmt.Printf("\n Task1Start TimeNow: ",time.Now())
    time.Sleep(1 * time.Second)  // 睡眠一秒
    fmt.Printf("\n Task1End TimeNow: ",time.Now())
    wg.Done()
    }

func task2()  {
    fmt.Printf("\n Task2Start TimeNow: ",time.Now())
    time.Sleep(2 * time.Second)
    fmt.Printf("\n Task2End TimeNow: ",time.Now())
    wg.Done()
    }

func main()  {
    wg.Add(3)
    fmt.Printf("\n CurTime: ",time.Now())
    go task1()
    go task2()

    //匿名goroutine
    go func() {//task3
        fmt.Printf("\n Task3Start TimeNow: ",time.Now())
        time.Sleep(2 * time.Second)
        fmt.Printf("\n Task3End TimeNow: ",time.Now())
        wg.Done()
    }()

    wg.Wait()
    fmt.Printf("\n End CurTime: ",time.Now())
}

/*
task1 + task2 + task的阻塞时间是 1 + 2 + 2 = 5s,在使用goroutine后只耗费了2s
 CurTime: %!(EXTRA time.Time=2018-01-22 21:31:19.405001 +0800 CST m=+0.005000301)
 Task3Start TimeNow: %!(EXTRA time.Time=2018-01-22 21:31:19.4210019 +0800 CST m=+0.021001201)
 Task1Start TimeNow: %!(EXTRA time.Time=2018-01-22 21:31:19.4210019 +0800 CST m=+0.021001201)
 Task2Start TimeNow: %!(EXTRA time.Time=2018-01-22 21:31:19.4210019 +0800 CST m=+0.021001201)
 Task1End TimeNow: %!(EXTRA time.Time=2018-01-22 21:31:20.4210591 +0800 CST m=+1.021058401)
 Task3End TimeNow: %!(EXTRA time.Time=2018-01-22 21:31:21.4211163 +0800 CST m=+2.021115601)
 Task2End TimeNow: %!(EXTRA time.Time=2018-01-22 21:31:21.4211163 +0800 CST m=+2.021115601)
 End CurTime: %!(EXTRA time.Time=2018-01-22 21:31:21.4211163 +0800 CST m=+2.021115601)
*/
  • runtime.GOMAXPROCS
    设置当前goroutine可使用的cpu最大数量, runtime.NumCPU() 此机器的cpu数量
func count()  {
    x := 0
    for i := 0; i < math.MaxInt32 ; i++ {
        x ++
    }
//  fmt.Println(x)
}

func task1(n int)  {
    for i := 0; i < n; i++ {
        count()
    }
}

func task2(n int)  {
    var wg sync.WaitGroup
    for i := 0; i < n; i++ {
        wg.Add(1)
        go func() {
            count()
            wg.Done()
        }()
    }
    wg.Wait()
}

func main() {
    n := 5
    start := time.Now().Second()
    task1(n)
    fmt.Printf("单线程共耗费时间: %v 秒 \n", time.Now().Second() - start)

    for i := 1; i <= runtime.NumCPU(); i ++ {
        start := time.Now().Second()
        runtime.GOMAXPROCS(i)  //设置goroutine可使用的最大cpu数量 runtime.NumCPU() 此机器的cpu数量
        task2(n)
        fmt.Printf("Cpu使用数量:%v, 共耗费时间: %v 秒 \n", i, time.Now().Second() - start)
    }
}

/*
单线程共耗费时间: 4 秒 
Cpu使用数量:1, 共耗费时间: 4 秒 
Cpu使用数量:2, 共耗费时间: 2 秒 
Cpu使用数量:3, 共耗费时间: 2 秒 
Cpu使用数量:4, 共耗费时间: 1 秒 
Cpu使用数量:5, 共耗费时间: 1 秒 
Cpu使用数量:6, 共耗费时间: 1 秒 
Cpu使用数量:7, 共耗费时间: 1 秒 
Cpu使用数量:8, 共耗费时间: 1 秒 
*/
  • 通道channel 阻塞线程
func main() {
    event := make(chan struct{})

    go func() {
        time.Sleep(3 * time.Second)
        close(event)
    }()

    <- event
    fmt.Println("End")
}
//当子线程close(event)后,程序才会结束
  • close()
func main() {
    a,b := make(chan int), make(chan int, 5)        // 默认为0  先进先出
    b <- 1
    b <- 2
    b <- 3
    fmt.Printf("a.len = %v  a.cap = %v \n", len(a), cap(a))  // a.len = 0  a.cap = 0 
    fmt.Printf("b.len = %v  b.cap = %v \n", len(b), cap(b))  // b.len = 3  b.cap = 5 

    close(b)    //如果channel被关闭了,就不可以往里放值,但是可以取值,而且不会死锁
    //b <- 4    panic: send on closed channel
    <- b
    <- b
    q, ok := <- b
    fmt.Println(q, ok) // 3 true
    q, ok = <- b
    fmt.Println(q, ok) // 0 false
}
  • 单向channel
    var b <-chan interface{} = make(chan interface{}, 5)        // 只能读
    var c chan<- interface{} = make(chan interface{}, 5)        // 只能写
  • channel的遍历
func main() {
    a := make(chan int, 3)
    a <- 10
    a <- 20
    a <- 30
    close(a) // 如果不加这个,循环的时候就会因为等待输出阻塞线程,导致死锁
    for i := range a{
        fmt.Println(i)
    }
}

func main() {
lenth :=  len(a)
    for i := 0; i < lenth; i++ {
        fmt.Println(<-a)
    }
}
  • 定时器
func main() {
    t := time.NewTicker(1 * time.Second)
    for  {
        select {
        case <- t.C:
            fmt.Println("End")
        }
    }
}
  • sync.Mutex
    防止两个线程同时使用一个资源,需要对资源加锁
func main() {
    var wg sync.WaitGroup
    a := 1
    b := 1
    wg.Add(4)

    var ml sync.Mutex
    // 不加锁

    go func() {
        for i := 0; i < 5000; i++ {
            b += 1
        }
        wg.Done()
    }()
    go func() {
        for i := 0; i < 5000; i++ {
            b += 1
        }
        wg.Done()
    }()

    // 加锁
    go func() {
        ml.Lock()
        for i := 0; i < 5000; i++ {
            a += 1
        }
        wg.Done()
        ml.Unlock()
    }()
    go func() {
        ml.Lock()
        for i := 0; i < 5000; i++ {
            a += 1
        }
        wg.Done()
        ml.Unlock()
    }()

    wg.Wait()

    fmt.Println("不加锁后计算的值",b)
    fmt.Println("加锁后计算的值",a)
}

//不加锁后计算的值 6842
//加锁后计算的值 10001
  • init
package LessonOther
import "fmt"

//init函数执行优先级高于main,
// 且可以有多个,
// 不可以被调用,
// 拼写必须是init
// 被其他包引用时也会调用
func init() {
    fmt.Println("init1")
}

func init() {
    fmt.Println("init2")
}

func init() {
    fmt.Println("init3")
}

func Get()  {
    fmt.Println("LessonOther -> Other.go -> Get 被调用")
}

package main

import "fmt"
import "../LessonOther"

func main() {
    LessonOther.Get()
    fmt.Println("main")
}

/*
init1
init2
init3
LessonOther -> Other.go -> Get 被调用
main
*/

你可能感兴趣的:(Golang学习笔记)