go语言四 channel和gorotime

goroutine

  go中使用Goroutine来实现并发concurrently。

  Goroutine是Go语言特有的名词。区别于进程Process,线程Thread,协程Coroutine,因为Go语言的创造者们觉得和他们是有所区别的,所以专门创造了Goroutine。

  Goroutine是与其他函数或方法同时运行的函数或方法。Goroutines可以被认为是轻量级的线程。与线程相比,创建Goroutine的成本很小,它就是一段代码,一个函数入口。以及在堆上为其分配的一个堆栈(初始大小为4K,会随着程序的执行自动增长删除)。因此它非常廉价,Go应用程序可以并发运行数千个Goroutines。

package main

import (
    "fmt"
    "time"
)

func hello() {
    fmt.Println("Hello world goroutine")
}
func main() {
    go hello()
    time.Sleep(50 * time.Microsecond)
    fmt.Println("main function")
}

临界资源安全问题:

首先看代码:

package main

import (
    "time"
    "math/rand"
    "fmt"
)

//全局变量
var ticket = 10 // 100张票

func main() {
    /*
    4个goroutine,模拟4个售票口,4个子程序操作同一个共享数据。
     */
    go saleTickets("售票口a") // g1,100
    go saleTickets("售票口b") // g2,100
    go saleTickets("售票口c") //g3,100
    go saleTickets("售票口d") //g4,100

    time.Sleep(5*time.Second)
}

func saleTickets(name string) {
    rand.Seed(time.Now().UnixNano())
    //for i:=1;i<=100;i++{
    //  fmt.Println(name,"售出:",i)
    //}
    for { //ticket=1
        if ticket > 0 { //g1,g3,g2,g4
            //睡眠
            time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
            // g1 ,g3, g2,g4
            fmt.Println(name, "售出:", ticket)  // 1 , 0, -1 , -2
            ticket--   //0 , -1 ,-2 , -3
        } else {
            fmt.Println(name,"没有票了。。")
            break
        }
    }
}

执行结果:

售票口b 售出: 10
售票口c 售出: 10
售票口d 售出: 10
售票口c 售出: 7
售票口a 售出: 6
售票口b 售出: 5
售票口d 售出: 4
售票口a 售出: 3
售票口a 售出: 2
售票口d 售出: 1
售票口d 没有票了。。
售票口c 售出: 0
售票口c 没有票了。。
售票口a 售出: -1
售票口a 没有票了。。
售票口b 售出: -2
售票口b 没有票了。。

至于什么原因,做过java的就不解释了,那么go是如何解决这个问题呢

waitgruop

看代码实例:

package main

import (
    "sync"
    "fmt"
)

var wg sync.WaitGroup
func main() {
    wg.Add(2)
    go fun()
    go fun2()
    fmt.Println("main进入阻塞状态。。。等待wg中的子goroutine结束。。")
    wg.Wait()
    fmt.Println("jieshu")
}
func fun(){
    defer wg.Done()
    for i :=0;i<10;i++{
        fmt.Println("woshi1   aaaaaaaaaaaa",i)
    }
}
func fun2(){
    //defer wg.Done()
    for i :=0;i<10;i++{
        fmt.Println("woshi1   ",i)
    }
    wg.Done()
}
main进入阻塞状态。。。等待wg中的子goroutine结束。。
woshi1   aaaaaaaaaaaa 0
woshi1    0
woshi1    1
woshi1    2
woshi1    3
woshi1    4
woshi1    5
woshi1    6
woshi1    7
woshi1    8
woshi1    9
woshi1   aaaaaaaaaaaa 1
woshi1   aaaaaaaaaaaa 2
woshi1   aaaaaaaaaaaa 3
woshi1   aaaaaaaaaaaa 4
woshi1   aaaaaaaaaaaa 5
woshi1   aaaaaaaaaaaa 6
woshi1   aaaaaaaaaaaa 7
woshi1   aaaaaaaaaaaa 8
woshi1   aaaaaaaaaaaa 9
jieshu

wg.wait方法,表示程序进入阻塞,等待其他goroutine执行完,再去执行线程下的代码

wg.add方法  表示添加几个goroutine

wg.done表示goroutine的代码执行完成了

lock:

看代码实例:

package main
import (
    "fmt"
    "time"
    "math/rand"
    "sync"
)

//全局变量,表示票
var ticket1 = 10 //100张票

var mutex sync.Mutex //创建锁头

var wg sync.WaitGroup //同步等待组对象
func main() {
    /*
    4个goroutine,模拟4个售票口,

    在使用互斥锁的时候,对资源操作完,一定要解锁。否则会出现程序异常,死锁等问题。
    defer语句
     */

    wg.Add(4)
    go saleTickets1("售票口1")
    go saleTickets1("售票口2")
    go saleTickets1("售票口3")
    go saleTickets1("售票口4")

    wg.Wait() //main要等待
    fmt.Println("程序结束了。。。")

    //time.Sleep(5*time.Second)
}

func saleTickets1(name string){
    rand.Seed(time.Now().UnixNano())
    defer wg.Done()
    for{
        //上锁
        mutex.Lock() //g2
        if ticket1 > 0{ //ticket 1 g1
            time.Sleep(time.Duration(rand.Intn(1000))*time.Millisecond)
            fmt.Println(name,"售出:",ticket1) // 1
            ticket1-- // 0
        }else{
            mutex.Unlock() //条件不满足,也要解锁
            fmt.Println(name,"售罄,没有票了。。")
            break
        }
        mutex.Unlock() //解锁
    }
}

 

执行结果:

GOROOT=D:\go\go1.13.6.windows-amd64\go #gosetup
GOPATH=D:\go\go1.13.6.windows-amd64\go\GOPATH #gosetup
D:\go\go1.13.6.windows-amd64\go\bin\go.exe build -i -o C:\Users\cxy\AppData\Local\Temp\___go_build_waut_go.exe D:/go/work/learngo/lerango/string/waut.go #gosetup
"D:\Program Files\JetBrains\ideaIU-2018.1.2.win\bin\runnerw.exe" C:\Users\cxy\AppData\Local\Temp\___go_build_waut_go.exe #gosetup
售票口1 售出: 10
售票口1 售出: 9
售票口2 售出: 8
售票口3 售出: 7
售票口4 售出: 6
售票口1 售出: 5
售票口2 售出: 4
售票口3 售出: 3
售票口4 售出: 2
售票口1 售出: 1
售票口2 售罄,没有票了。。
售票口4 售罄,没有票了。。
售票口3 售罄,没有票了。。
售票口1 售罄,没有票了。。
程序结束了。。。

Process finished with exit code 0

还有读写锁,也是如此:

  1. 读锁不能阻塞读锁
  2. 读锁需要阻塞写锁,直到所有读锁都释放
  3. 写锁需要阻塞读锁,直到所有写锁都释放
  4. 写锁需要阻塞写锁

channel

package main

import (
    "fmt"
    "time"
)

func main() {
    ch1 := make(chan int)
    bools := make(chan bool)
    go func() {
        fmt.Println("1111   执行")
        time.Sleep(3* time.Second)
        data := <-ch1
        fmt.Println(data)
        bools <- true
    }()
    time.Sleep(5*time.Second)
    ch1 <-100
     a :=<- bools
     fmt.Println(a)
    fmt.Println("main。。over")
}

结果:

GOROOT=D:\go\go1.13.6.windows-amd64\go #gosetup
GOPATH=D:\go\go1.13.6.windows-amd64\go\GOPATH #gosetup
D:\go\go1.13.6.windows-amd64\go\bin\go.exe build -i -o C:\Users\cxy\AppData\Local\Temp\___go_build_cha_go.exe D:/go/work/learngo/lerango/string/cha.go #gosetup
"D:\Program Files\JetBrains\ideaIU-2018.1.2.win\bin\runnerw.exe" C:\Users\cxy\AppData\Local\Temp\___go_build_cha_go.exe #gosetup
1111   执行
100
true
main。。over

Process finished with exit code 0

 

posted @ 2020-02-04 21:56  菩提树下的丁春秋  阅读(360)  评论(0编辑  收藏  举报