zoukankan      html  css  js  c++  java
  • Go 缓冲信道

    缓冲信道

    语法结构:cap为容量

    ch := make(chan type, cap)
    • 缓冲信道支持len()和cap()。
    • 只能向缓冲信道发送容量以内的数据。
    • 只能接收缓冲信道长度以内的数据。
    • 缓冲信道的容量是指信道可以存储的值的数量。我们在使用 make 函数创建缓冲信道的时候会指定容量大小。
    • 缓冲信道的长度是指信道中当前排队的元素个数。

    信道是异步的,是一种在被创建时就被开辟了能存储一个或者多个值的信道。
    这种类型并不要求发送与接收同时进行。只要缓冲区有未使用空间用于发送数据,或还包含可以接收的数据,那么其通信就会无阻塞地进行。只有在通道中没有要接收的值时,接收动作才会阻塞。

    示例一

    package main
    import (
    	"fmt"
    )
    func main() {
    	//创建一个容量为3的缓冲信道
    	ch := make(chan string, 3)
    	ch <- "naveen"
    	ch <- "paul"
    	fmt.Println("capacity is", cap(ch))   //capacity is 3
    	fmt.Println("length is", len(ch))     //length is 2
    	fmt.Println("read value", <-ch)       //read value naveen
    	fmt.Println("new length is", len(ch)) //new length is 1
    }
    

       

    示例二

    package main
    import (
    	"fmt"
    	"time"
    )
    func write(ch chan int) {
    	for i := 0; i < 5; i++ {
    		ch <- i
    		fmt.Println("successfully wrote", i, "to ch")
    	}
    	close(ch)
    }
    
    func main() {
    	ch := make(chan int, 2)
    	go write(ch)
    	time.Sleep(2 * time.Second)
    	for v := range ch {
    		fmt.Println("read value", v,"from ch")
    		time.Sleep(2 * time.Second)
    	}
    } 

    创建一个两个容量的信道。
    write协程先向信道里写入两个数据,然后阻塞,并打印,主协程睡眠两秒。
    两秒后,主协程从信道中读取一个数据,并睡眠两秒,此时write协程继续向信道里写入一个数据,然后阻塞,等待主协程两秒后读取数据。


    死锁

    package main
    import (
    	"fmt"
    )
    func main() {
    	ch := make(chan string, 2)
    	ch <- "naveen"
    	ch <- "paul"
    	ch <- "steve"
    	fmt.Println(<-ch)
    	fmt.Println(<-ch)
    }

    当我们向信道写入数据时,超出了信道的容量,因此写入发生了阻塞。现在想要写操作能够进行下去,必须要有其它协程来读取这个信道的数据。
    但在程序中,并没有并发协程来读取这个信道,因此这里会发生死锁(deadlock)。

     

    WaitGroup

    假设我们有 3 个并发执行的 Go 协程(由Go 主协程生成)。Go 主协程需要等待这 3 个协程执行结束后,才会终止。这就可以用 WaitGroup 来实现。

    package main
    
    import (
        "fmt"
        "sync"
        "time"
    )
    
    func process(i int, wg *sync.WaitGroup) {
        fmt.Println("started Goroutine ", i)
        time.Sleep(2 * time.Second)
        fmt.Printf("Goroutine %d ended
    ", i)
        //Done方法减少WaitGroup计数器的值,应在线程的最后执行。
        wg.Done()
    }
    
    /*
        WaitGroup用于等待一组线程的结束。
        父线程调用Add方法来设定应等待的线程的数量。
        每个被等待的线程在结束时应调用Done方法。
        同时,主线程里可以调用Wait方法阻塞至所有线程结束。
    */
    func main() {
        no := 3
        var wg sync.WaitGroup
        //并发协程
        for i := 0; i < no; i++ {
            /*
                Add方法向内部计数加上delta,delta可以是负数;
                如果内部计数器变为0,Wait方法阻塞等待的所有线程都会释放,
                如果计数器小于0,方法panic。
            */
            wg.Add(1)
            go process(i, &wg)
        }
        //Wait方法阻塞直到WaitGroup计数器减为0。
        wg.Wait()
        fmt.Println("over")
    }
    

     

  • 相关阅读:
    C#转C++的一点分享
    数据挖掘十大经典算法
    在硅谷面试:如何证明你是最优秀的?
    .NET技术+25台服务器怎样支撑世界第54大网站
    如何将Vim打造成一个成熟的IDE
    24点算法
    12个Web设计师必备的Bootstrap工具
    程序员必须进行的10项投资
    转载:传说中的T检验
    三测
  • 原文地址:https://www.cnblogs.com/-wenli/p/11824921.html
Copyright © 2011-2022 走看看