通道

作者: isuntong | 来源:发表于2020-03-25 21:54 被阅读0次

    channel通道

    package main
    
    import "fmt"
    
    //15
    func main() {
        /*
        channel
        */
    
        var a chan int
        fmt.Printf("%T,%v\n",a,a) //chan int,<nil>
    
        if a == nil {
            fmt.Println("channel是nil的,不能使用,需要先创建通道")
            a = make(chan int)
            fmt.Println(a) //0xc00008c060
        }
    
        test1(a)
    
        var ch1 chan bool
        ch1 = make(chan bool)
    
        go func() {
            for i := 0; i < 10; i++ {
                fmt.Println("子goroutine:",i)
            }
            //循环结束,向通道中写数据
            ch1 <- true
            fmt.Println("结束。。。") //结束。。。
        }()
    
        //写之前读阻塞,读之前写阻塞
        data := <- ch1
        fmt.Println("main data --->",data) //main data ---> true
        fmt.Println("main over") //main over
    }
    
    func test1(ch chan int){
        fmt.Printf("%T,%v\n",ch,ch) //chan int,0xc000100060
    }
    

    关闭通道和通道上范围循环

    package main
    
    import (
        "fmt"
        "time"
    )
    
    //16
    func main() {
        /*
        关闭通道:close(ch)
            子groutine,写出10个数据
                每写一个,阻塞一次,主goroutine读取一次,解除阻塞
    
            主goroutine,读取数据
                每次读取数据,阻塞一次,子goroutine,写出一个,解除阻塞
    
        */
        ch1 := make(chan int)
        go sendData(ch1)
    
        //读取通道的数据
        for{
            time.Sleep(1 * time.Second)
            v,ok := <- ch1
            if !ok {
                fmt.Println("已经读取了所有数据",v,ok)
                break
            }
            fmt.Println("读取的数据:",v,ok)
        }
        fmt.Println("main over")
    
    }
    
    func sendData(ch1 chan int)  {
        //发送方
        for i := 0; i < 10; i++ {
            ch1 <- i
        }
        close(ch1)
    }
    
    
    package main
    
    import (
        "fmt"
    )
    
    //17
    func main() {
        /*
        通过range访问通道
        */
        ch1 := make(chan int)
        go sendData2(ch1)
    
        //range来访问通道
        for v := range ch1 {
            fmt.Println("读取数据:",v)
        }
        fmt.Println("main over")
    
    }
    
    func sendData2(ch1 chan int)  {
        //发送方
        for i := 0; i < 10; i++ {
            ch1 <- i
        }
        close(ch1) //通知对方通道关闭
    }
    
    

    缓冲通道

    package main
    
    import (
        "fmt"
        "strconv"
    )
    
    //18
    func main() {
        /*
            非缓冲通道:make(chan T)
                一次发送,一次接受,都是阻塞的
            缓冲通道:make(chan T,capacity)
                发送:缓冲区的数据满了,才会阻塞
                接收:缓冲区的数据空了,才会阻塞
        */
        ch1 := make(chan int)
        fmt.Println(len(ch1), cap(ch1)) //0 0
    
        ch2 := make(chan int, 5)
        fmt.Println(len(ch2), cap(ch2)) //0 5
    
        ch2 <- 100
        fmt.Println(len(ch2), cap(ch2)) //1 5
    
        ch2 <- 100
        ch2 <- 200
        ch2 <- 300
        ch2 <- 400
        fmt.Println(len(ch2), cap(ch2)) //5 5
    
        // ch2 <- 600 //fatal error: all goroutines are asleep - deadlock!
    
        fmt.Println("-------------")
        ch3 := make(chan string, 4)
        go sendData3(ch3)
    
        for{
            v,ok := <-ch3
            if !ok {
                fmt.Println("读完了..",ok)
                break
            }
            fmt.Println("\t读取的数据是:",v)
        }
        fmt.Println("main over...")
    
    }
    
    func sendData3(ch chan string){
        for i := 0; i < 10; i++ {
            ch <- "数据" + strconv.Itoa(i)
            fmt.Println("子goroutine中写出第 %d 个数据\n",i)
        }
        close(ch)
    }
    
    

    定向通道

    package main
    
    import "fmt"
    
    //19
    func main() {
        /*
            双向通道
                chan T
                    chan <- data,发送数据,写出
                    data <- chan,获取数据,读取
    
            单向:定向
                chan <- T,只支持写操作
                <- chan T,只读
        */
        ch1 := make(chan string)
        done := make(chan bool)
        go sendData4(ch1, done)
    
        data := <- ch1
        fmt.Println("子goroutine传来:",data) //子goroutine传来: isuntong
    
        ch1 <- "isuntong2"
    
        <- done //不通知不要结束
        fmt.Println("main over...")
    
    }
    
    func sendData4(ch1 chan string, done chan bool) {
        ch1 <- "isuntong"
    
        data := <- ch1
        fmt.Println("main goroutine传来:",data)
    
        done <- true
    }
    
    
    package main
    
    import "fmt"
    
    //20
    func main() {
        /*
            单向:定向
                chan <- T,只支持写操作
                <- chan T,只读
    
        用作默写函数保护
        函数内部对于ch1只能读,不能写,所以可以保护安全
    
        创建双向channel,在某些函数中限定只读只写,作为保护。
    
        */
        ch1 := make(chan int) //双向,读写
        //ch2 := make(chan <- int) //单向,只能写
        //ch3 := make(<- chan int) //单向,只能读
    
        // ch2 <- 1000
        // data := <-ch2 //invalid operation: <-ch2 (receive from send-only type chan<- int)
    
        // data := <- ch3
        // ch3 <- 2000 //invalid operation: ch3 <- 2000 (send to receive-only type <-chan int)
        // fmt.Println(data)
    
        go fun3(ch1) //可读可写
        // fun3(ch2)
    
        data2 := <- ch1
        fmt.Println("fun3函数写出的数据是:",data2) //fun3函数写出的数据是: 100
    
    }
    
    //该函数,只能操作只写的通道
    func fun3(ch chan <- int) {
        ch <- 100
        fmt.Println("fun3函数结束") //fun3函数结束
    }
    
    func fun4(ch <- chan int) {
    
        fmt.Println("fun3函数结束") //fun3函数结束
    }
    
    

    time包中的通道相关函数

    package main
    
    import (
        "fmt"
        "time"
    )
    
    //21
    func main() {
        /*
            1. func NewTimer(d Duration) *Timer
                创建一个计数器,d时间以后触发
    
            2. func After(d Duration) <- chan Time
                返回一个通道,存储的是d时间间隔之后的当前时间
    
        */
        timer := time.NewTimer(3 * time.Second)
        fmt.Printf("%T\n",timer) //*time.Timer
        fmt.Println(time.Now()) //2020-03-26 19:29:30.612334 +0800 CST m=+0.000112607
    
        //此处等待channel中的数据,会阻塞3秒
        ch2 := timer.C
        fmt.Println(<-ch2) //2020-03-26 19:29:33.614302 +0800 CST m=+3.002032115
    
        //新建一个计数器
        timer2 := time.NewTimer(5 * time.Second)
        //开始goroutine,来处理触发后的事件
        go func() {
            <- timer2.C
            fmt.Println("Timer2结束")
        }()
    
        time.Sleep(3 * time.Second)
        flag := timer2.Stop() //停止定时
        if flag {
            fmt.Println("Timer2停止了")
        }
    
    
        //After(d Duration)
        ch := time.After(3 * time.Second)
        fmt.Printf("%T\n",ch) //<-chan time.Time
        fmt.Println(time.Now()) //2020-03-26 19:40:21.089133 +0800 CST m=+6.004003279
    
        timer3 := <-ch
        fmt.Println(timer3) //2020-03-26 19:40:24.091121 +0800 CST m=+9.005942476
    
    }
    

    select语句

    package main
    
    import (
        "fmt"
        "time"
    )
    
    //22
    func main() {
        /*
        分支语句:if、switch、select
        select类似于switch语句
            但是select语句会随机执行一个可运行的case
            如果没有case可以执行,要看是否有default,如果有就执行default,否则就进入阻塞,直到有case可以运行
    
    
         */
    
        ch1 := make(chan int)
        ch2 := make(chan int)
    
        go func() {
            time.Sleep(3 * time.Second)
            ch1 <- 100
        }()
    
        go func() {
            time.Sleep(3 * time.Second)
            ch2 <- 200
        }()
    
        select {
        case num1 := <- ch1:
            fmt.Println("ch1中获得数据是:", num1)
        case num2,ok := <-ch2:
            if ok{
                fmt.Println("ch2中获得的数据是:",num2)
            }else {
                fmt.Println("ch2通道已关闭")
            }
        default:
            fmt.Println("default语句。。。")
    
        }
    
        fmt.Println("main over...")
    
    }
    

    CSP并发模型

    相关文章

      网友评论

          本文标题:通道

          本文链接:https://www.haomeiwen.com/subject/qguxuhtx.html