zoukankan      html  css  js  c++  java
  • 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:gogo1.13.6.windows-amd64go #gosetup
    GOPATH=D:gogo1.13.6.windows-amd64goGOPATH #gosetup
    D:gogo1.13.6.windows-amd64goingo.exe build -i -o C:UserscxyAppDataLocalTemp\___go_build_waut_go.exe D:/go/work/learngo/lerango/string/waut.go #gosetup
    "D:Program FilesJetBrainsideaIU-2018.1.2.winin
    unnerw.exe" C:UserscxyAppDataLocalTemp\___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:gogo1.13.6.windows-amd64go #gosetup
    GOPATH=D:gogo1.13.6.windows-amd64goGOPATH #gosetup
    D:gogo1.13.6.windows-amd64goingo.exe build -i -o C:UserscxyAppDataLocalTemp\___go_build_cha_go.exe D:/go/work/learngo/lerango/string/cha.go #gosetup
    "D:Program FilesJetBrainsideaIU-2018.1.2.winin
    unnerw.exe" C:UserscxyAppDataLocalTemp\___go_build_cha_go.exe #gosetup
    1111   执行
    100
    true
    main。。over
    
    Process finished with exit code 0
  • 相关阅读:
    Bundle类
    AlertDialog
    认识Android
    TextView属性详解
    Android中设置文字大小的定义类型
    理解偏差
    python爬虫实验2
    python爬虫实验
    PHP sql注入漏洞修复(字符串型)
    java实现远程控制
  • 原文地址:https://www.cnblogs.com/xiufengchen/p/12261670.html
Copyright © 2011-2022 走看看