通道

2020-03-25  本文已影响0人  isuntong

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并发模型

上一篇下一篇

猜你喜欢

热点阅读