• 速战速决 go go 高级: 线程间通信 channel/select


    速战速决 go https://github.com/webabcd/GoSample
    作者 webabcd

    速战速决 go - go 高级: 线程间通信 channel/select

    示例如下:

    advanced/goroutine2.go

    // go 高级 - 线程间通信 channel/select
    // goroutine 相当于轻量级的线程(相对于传统线程来说效率要高出很多),通过 go 关键字创建 goroutine,通过 channel 做 goroutine 间的通信
    // 说明:
    // 1、一个 goroutine 向 channel 发送数据,另一个 goroutine 从 channel 接收数据(这是要阻塞的,直到接收到数据为止)
    // 2、无缓冲区 channel 的意思是:写数据和读数据是一套动作,完成一套动作后才能执行下一套动作
    //    向 channel 写数据时,如果 channel 中有数据未读,则是不能写的,要阻塞着
    // 3、有缓冲区 channel 的意思是:向缓冲区写数据和从缓冲区读数据是分别进行的,缓冲区是先入先出的
    //    只要缓冲区不满,即使没人读,也可以继续向缓冲区写数据,如果缓冲区满了,就要阻塞了
    
    package advanced
    
    import (
    	"fmt"
    	"time"
    )
    
    func Goroutine2Sample() {
    
    	// 无缓冲区 channel 的 demo
    	goroutine2_sample1()
    
    	// 有缓冲区 channel 的 demo
    	goroutine2_sample2()
    
    	// select 的 demo
    	// 本例演示了如何通过 select 为 channel 增加读取超时的判断
    	goroutine2_sample3()
    }
    
    func goroutine2_sample1() {
    
    	// 创建一个可以传输 int 类型数据的 channel(注:创建 channel 时必须指定传输的数据类型,每个 channel 只能传输你指定的数据类型)
    	var ch chan int = make(chan int)
    
    	// 创建一个只写的 channel
    	// var ch_sendOnly chan<- int = make(chan int)
    	// var ch_sendOnly chan<- int = make(chan<- int)
    
    	// 创建一个只读的 channel
    	// var ch_recvOnly <-chan int = make(chan int)
    	// var ch_recvOnly <-chan int = make(<-chan int)
    
    	go func() {
    		for i := 0; i < 5; i++ {
    			fmt.Println("准备写入", i)
    			// 通过 channel<- 向 channel 发送数据(即写数据)
    			// 如果 channel 中有未读数据,则阻塞
    			ch <- i
    			fmt.Println("已经写入", i)
    		}
    
    		// 关闭 channel
    		close(ch)
    	}()
    
    	// 通过 <-channel 从 channel 接收数据(即读数据)
    	// 这是要阻塞的,直到读出为止
    	data := <-ch
    	fmt.Println("已经读出", data)
    
    	// 遍历 channel 中的数据
    	for data := range ch {
    		fmt.Println("已经读出", data)
    	}
    
    	// 判断 channel 是否关闭了(返回 false 则说明 channel 已经关闭了)
    	_, ok := <-ch
    	fmt.Println("channel状态", ok)
    
    	// 我这里某一次的运行结果如下:
    	/*
    		准备写入 0
    		已经写入 0
    		准备写入 1
    		已经读出 0
    		已经读出 1
    		已经写入 1
    		准备写入 2
    		已经写入 2
    		准备写入 3
    		已经读出 2
    		已经读出 3
    		已经写入 3
    		准备写入 4
    		已经写入 4
    		已经读出 4
    		channel状态 false
    	*/
    }
    
    func goroutine2_sample2() {
    	// 创建 channel 时指定缓冲区的大小(默认是无缓冲区的)
    	// 这个缓冲区的大小指的是可以保存的元素的数量
    	ch := make(chan int, 5)
    
    	go func() {
    		for i := 0; i < 5; i++ {
    			fmt.Println("准备写入", i)
    			// 通过 channel<- 向缓冲区发送数据(即写数据)
    			// 如果缓冲区满了,则阻塞
    			ch <- i
    			fmt.Println("已经写入", i)
    		}
    
    		// 关闭 channel
    		close(ch)
    	}()
    
    	time.Sleep(time.Second)
    	for i := 0; i < 5; i++ {
    		// 通过 <-channel 从缓冲区接收数据(即读数据)
    		// 这是要阻塞的,直到读出为止
    		data := <-ch
    		fmt.Println("已经读出", data, len(ch)) // len() 可以获取 channel 的缓冲区中的元素的数量
    	}
    
    	// 判断 channel 是否关闭了(返回 false 则说明 channel 已经关闭了)
    	_, ok := <-ch
    	fmt.Println("channel状态", ok)
    
    	// 我这里某一次的运行结果如下:
    	/*
    		准备写入 0
    		已经写入 0
    		准备写入 1
    		已经写入 1
    		准备写入 2
    		已经写入 2
    		准备写入 3
    		已经写入 3
    		准备写入 4
    		已经写入 4
    		已经读出 0 4
    		已经读出 1 3
    		已经读出 2 2
    		已经读出 3 1
    		已经读出 4 0
    		channel状态 false
    	*/
    }
    
    func goroutine2_sample3() {
    	ch := make(chan int)
    	quit := make(chan bool)
    
    	go func() {
    		for {
    			// select 中的 case 必须是读 channel 或写 channel
    			// 每次执行时,select 都会评估每个 case 语句
    			//   1、如果存在可以执行的 case(即没有被阻塞),则从可以执行的 case 中随机选择一个执行
    			//   2、如果不存在可以执行的 case
    			//      a) 有 default 时:执行 default
    			//      b) 没 default 时:阻塞,直到有 case 可以执行为止
    			select {
    			case data := <-ch:
    				fmt.Println(time.Now(), "读出", data)
    			case <-time.After(3 * time.Second):
    				fmt.Println(time.Now(), "从 ch 通道中获取数据超时了,超时时间是 3 秒")
    				quit <- true
    			}
    		}
    	}()
    
    	for i := 0; i < 5; i++ {
    		ch <- i
    		time.Sleep(time.Second)
    	}
    
    	// 阻塞,直到从 quit 通道中收到数据为止
    	<-quit
    
    	fmt.Println(time.Now(), "结束")
    
    	// 我这里某一次的运行结果如下:
    	/*
    		2022-02-07 16:29:07.8439862 +0800 CST m=+0.006806901 读出 0
    		2022-02-07 16:29:08.8481389 +0800 CST m=+1.010959601 读出 1
    		2022-02-07 16:29:09.8511351 +0800 CST m=+2.013955801 读出 2
    		2022-02-07 16:29:10.8637841 +0800 CST m=+3.026604801 读出 3
    		2022-02-07 16:29:11.8757439 +0800 CST m=+4.038564601 读出 4
    		2022-02-07 16:29:14.8760507 +0800 CST m=+7.038871401 从 ch 通道中获取数据超时了,超时时间是 3 秒
    		2022-02-07 16:29:14.8760507 +0800 CST m=+7.038871401 结束
    	*/
    }
    
    

    速战速决 go https://github.com/webabcd/GoSample
    作者 webabcd

  • 相关阅读:
    原始套接字-自定义IP首部和TCP首部
    原始套接字-TCP/IP下三层数据显示
    ARP欺骗分析
    博弈论
    C++ map & set
    selenium+chrome配置环境
    windows下安装python+selenium
    python之configParser模块读写配置文件
    接口测试流程
    Python之读取文件配置
  • 原文地址:https://www.cnblogs.com/webabcd/p/go_advanced_goroutine2.html
Copyright © 2020-2023  润新知