Go通道笔记

xiongkun01 · · 418 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

package main

import (
    "fmt"
    "sync"
    "time"
    "unsafe"
)

func main10() {
    done := make(chan struct{}) // 结束事件
    c := make(chan string)      // 数据传输通道

    go func() {
        s := <-c // 接受消息
        println(s)
        close(done) // 关闭通道,作为结束通知
    }()

    c <- "hi!" // 发送消息
    <-done     // 阻塞,直到有数据或者管道关闭
}

func main11() {
    c := make(chan int, 3) // 创建带 3 个缓冲槽的异步通道

    c <- 1 // 缓冲区未满,不会阻塞
    c <- 2

    println(<-c) // 缓冲区尚有数据,不会阻塞
    println(<-c)
}

// 缓冲区大小是内部属性,不属于类型组成部分。另外通道变量本身就是指针,可以用相等操作符判断是否为同一对象或者nil
func main12() {
    var a, b chan int = make(chan int, 3), make(chan int)
    var c chan bool

    println(a == b)
    println(c == nil)

    fmt.Printf("%p, %d\n", a, unsafe.Sizeof(a))
}

// 对于同步通道 len() 和 cap() 都返回0
func main13() {
    a, b := make(chan int), make(chan int, 3)

    b <- 1
    b <- 2

    println("a:", len(a), cap(a))
    println("b:", len(b), cap(b))
}

func main14() {
    c := make(chan int)

    go func() {
        defer close(c) // 关闭通道
        println("sub ....")
    }()

    <-c // 阻塞直到通道关闭
    print("main ....")
}

func main15() {
    done := make(chan struct{})
    c := make(chan int)

    go func() {
        defer close(done)

        //for {
        //    x, ok := <-c
        //    if !ok {
        //        return
        //    }
        //
        //    println(x)
        //}
        for x := range c { // 循环获取消息,直到通道被关闭
            println(x)
        }
    }()

    c <- 1
    c <- 2
    c <- 3
    close(c)
    <-done
}

// 通知可以是群体性的
func main16() {
    var wg sync.WaitGroup
    ready := make(chan struct{})

    for i := 0; i < 3; i++ {
        wg.Add(1)

        go func(id int) {
            defer wg.Done()

            println(id, ": ready")
            <-ready
            println(id, ": running...")
        }(i)
    }

    time.Sleep(time.Second)
    println("Ready? Go!")

    close(ready)

    wg.Wait()
}

func main17() {
    c := make(chan int, 3)

    c <- 1
    c <- 2
    close(c)

    for i := 0; i < cap(c)+1; i++ {
        x, ok := <-c
        println(i, ":", ok, x)
    }
}

// 单向通道,close不能用于接收端,不可逆
func main18() {
    var wg sync.WaitGroup
    wg.Add(2)

    c := make(chan int)
    var send chan<- int = c
    var recv <-chan int = c

    go func() {
        defer wg.Done()

        for x := range recv {
            println(x)
        }
    }()

    go func() {
        defer wg.Done()
        defer close(c)

        for i := 0; i < 5; i++ {
            send <- i
        }
    }()

    wg.Wait()
}

// select 同时处理多个通道,它会随机选择一个可用通道做收发操作
// 如果要等到全部通道消息处理结束,可将已完成通道设置为 nil. 这样它就会被阻塞,不再被选select选中
func main19() {
    var wg sync.WaitGroup
    wg.Add(3)

    a, b := make(chan int), make(chan int)

    go func() {
        defer wg.Done()

        for {
            var (
                x    int
                ok   bool
            )

            select { // 随机选择可用 channel 接收数据
            case x, ok = <-a:
                if !ok {
                    a = nil
                    break
                }
                println("a", x)
            case x, ok = <-b:
                if !ok {
                    b = nil
                    break
                }
                println("b", x)
            }

            if a == nil && b == nil { // 全部结束,退出循环
                return
            }
        }
    }()

    go func() {
        defer wg.Done()
        defer close(a)

        for i := 0; i < 3; i++ {
            //select { // 随机选择发送 channel
            //case a <- i:
            //case b <- i * 10:
            //}
            a <- i
        }
    }()

    go func() {
        defer wg.Done()
        defer close(b)

        for i := 0; i < 5; i++ {
            b <- i * 10
        }
     }()

    wg.Wait()
}

func main20() {
    done := make(chan int)
    c := make(chan int)

    go func() {
        defer close(done)

        for {
            select {
            case x, ok := <- c:
                if !ok {
                    return
                }

                fmt.Println("data:", x)
            default: // 避免select阻塞
            }

            fmt.Println(time.Now())
            time.Sleep(time.Second)
        }
    }()

    time.Sleep(time.Second * 5)
    c <- 100
    close(c)

    <-done
}

func main21() {
    done := make(chan struct{})

    data := []chan int {
        make(chan int, 3),
    }

    go func() {
        defer close(done)

        for i := 0; i < 10; i++ {
            select {
            case data[len(data) - 1] <- i:
            default:
                data = append(data, make(chan int, 3))
            }
        }
    }()

    <-done

    for i := 0; i < len(data); i++ {
        c := data[i]
        close(c)

        for x := range c {
            println(x)
        }
    }
}

type receiver struct {
    sync.WaitGroup
    data chan int
}

func newReceiver() *receiver {
    r := &receiver{
        data: make(chan int),
    }

    r.Add(1)
    go func() {
        defer r.Done()
        for x := range r.data { // 接收消息,直到通道关闭
            println("recv:", x)
        }
    }()

    return r
}

func main22() {
    r := newReceiver()
    r.data <- 1
    r.data <- 2
    r.data <- 1
    r.data <- 2
    r.data <- 1
    r.data <- 2

    close(r.data)
    r.Wait()
}

type pool chan []byte

func newPool(cap int) pool {
    return make(chan []byte, cap)
}

func (p pool) get() []byte {
    var v []byte

    select {
    case v = <- p:
    default:
        v = make([]byte, 10)
    }

    return v
}

func (p pool) put(b []byte) {
    select {
    case p <- b:
    default:
    }
}









有疑问加站长微信联系(非本文作者)

本文来自:Segmentfault

感谢作者:xiongkun01

查看原文:Go通道笔记

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

418 次点击  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传