github.com/szq-123/codingpractice@v0.0.0-20240430111904-2778dfaf7994/golang/channel_test.go (about)

     1  package golang
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  	"time"
     7  )
     8  
     9  // goroutine src/runtime/runtime2.go
    10  
    11  // channel src/runtime/chan.go
    12  // refer to `sudog`
    13  
    14  // Sending to a full channel shall block the goroutine, until receiver draws one out of the channel so the channel is no longer full.
    15  func TestSend2Full(t *testing.T) {
    16  	ch := make(chan int, 3)
    17  	go func() {
    18  		time.Sleep(5 * time.Second)
    19  		<-ch
    20  	}()
    21  
    22  	for i := 0; i < 4; i++ {
    23  		ch <- 1
    24  	}
    25  
    26  	println("channel block stops")
    27  }
    28  
    29  // fetching data from empty channel, resulting in blocking the receiver goroutine.
    30  func TestFetchFromEmpty(t *testing.T) {
    31  	ch := make(chan int)
    32  	go func() {
    33  		for {
    34  			fmt.Printf("go routine1: %d\n", <-ch)
    35  		}
    36  	}()
    37  	go func() {
    38  		for {
    39  			fmt.Printf("go routine2: %d\n", <-ch)
    40  		}
    41  	}()
    42  
    43  	for i := 0; ; i = 1 - i {
    44  		ch <- i
    45  		time.Sleep(time.Second)
    46  	}
    47  }
    48  
    49  func TestForRange(t *testing.T) {
    50  	ch := make(chan int, 2)
    51  
    52  	// `for-range` traverses channel. if channel is empty, it's blocked. if channel is closed, it's over.
    53  	go func() {
    54  		for x := range ch {
    55  			fmt.Printf("go routine: %d\n", x)
    56  			time.Sleep(time.Second)
    57  		}
    58  		fmt.Println("go routine: channel has been closed")
    59  	}()
    60  
    61  	for i := 0; i < 5; i++ {
    62  		ch <- 1
    63  		fmt.Printf("main thread: %d\n", i)
    64  	}
    65  	close(ch)
    66  	time.Sleep(10 * time.Second)
    67  }
    68  
    69  func TestFetchFromClosed(t *testing.T) {
    70  	ch := make(chan int, 2)
    71  
    72  	// fetch data from closed channel. the received are the default value of channel's underlying type.
    73  	go func() {
    74  		for {
    75  			fmt.Printf("go routine: %d\n", <-ch)
    76  			time.Sleep(time.Second)
    77  		}
    78  	}()
    79  
    80  	for i := 0; i < 3; i++ {
    81  		ch <- 1
    82  		fmt.Printf("main thread: %d\n", i)
    83  	}
    84  	close(ch)
    85  	time.Sleep(10 * time.Second)
    86  }
    87  
    88  func TestSend2Closed(t *testing.T) {
    89  	ch := make(chan int, 2)
    90  
    91  	// Sending datum to closed channel, causing panic.
    92  	go func() {
    93  		for i := 0; i < 5; i++ {
    94  			fmt.Printf("go routine: %d\n", <-ch)
    95  			time.Sleep(time.Second)
    96  		}
    97  		close(ch)
    98  	}()
    99  
   100  	for i := 0; i < 10; i++ {
   101  		ch <- 1
   102  		fmt.Printf("main thread: %d\n", i)
   103  	}
   104  
   105  	time.Sleep(10 * time.Second)
   106  }
   107  
   108  func TestOkJudge(t *testing.T) {
   109  	ch := make(chan int, 2)
   110  
   111  	// `ok` semantics, helping you judge whether channel closes.
   112  	go func() {
   113  		for {
   114  			x, ok := <-ch
   115  			if ok {
   116  				fmt.Printf("go routine: %d\n", x)
   117  				time.Sleep(time.Second)
   118  			} else {
   119  				fmt.Println("go routine: channel has been closed")
   120  				break
   121  			}
   122  		}
   123  	}()
   124  
   125  	for i := 0; i < 3; i++ {
   126  		ch <- 1
   127  		fmt.Printf("main thread: %d\n", i)
   128  	}
   129  	close(ch)
   130  	time.Sleep(10 * time.Second)
   131  }
   132  
   133  // `Select` source code: runtime/select.go
   134  
   135  // `for-select`, https://programs.wiki/wiki/analysis-of-go-bottom-series-select-principle.html
   136  // select does not cycle(circulate, recur) itself.
   137  func TestSelectGet(t *testing.T) {
   138  	ch1 := make(chan int, 2)
   139  
   140  	// randomly select a case from ready ones, get data from it and execute. if no default statement here and no case ready, it's blocked.
   141  	// quit a goroutine through `done` channel. mention that a closed channel bring out zero-value.
   142  	done := make(chan int)
   143  	go func() {
   144  		for {
   145  			select {
   146  			case <-done:
   147  				fmt.Printf("go routine done, exit")
   148  				return
   149  			case x := <-ch1:
   150  				fmt.Printf("go routine ch1: %d\n", x)
   151  			case x := <-time.After(4 * time.Second):
   152  				fmt.Printf("go routine time out: %v\n", x)
   153  				//default:
   154  				//	fmt.Println("go routine nothing from channel")
   155  				//	time.Sleep(500 *time.Millisecond)
   156  			}
   157  		}
   158  	}()
   159  
   160  	for i := 0; i < 5; i++ {
   161  		ch1 <- i
   162  		time.Sleep(time.Second)
   163  	}
   164  	close(done)
   165  	time.Sleep(5 * time.Second)
   166  }
   167  
   168  func TestSelectSend(t *testing.T) {
   169  	// randomly select a channel and send data随机选择一个管道,向其发送数据并执行,管道满则该case阻塞
   170  	ch1 := make(chan int, 2)
   171  	ch2 := make(chan int, 2)
   172  	go func() {
   173  		for {
   174  			select {
   175  			case ch1 <- 1:
   176  				fmt.Printf("go routine ch1: %d\n", 1)
   177  			case ch2 <- 1:
   178  				fmt.Printf("go routine ch2: %d\n", 1)
   179  			default:
   180  				fmt.Println("channel are filled with data!")
   181  				time.Sleep(2 * time.Second)
   182  			}
   183  		}
   184  	}()
   185  
   186  	for i := 0; i < 5; i++ {
   187  		<-ch1
   188  		<-ch2
   189  		time.Sleep(time.Second)
   190  	}
   191  	time.Sleep(10 * time.Second)
   192  }
   193  
   194  // single-direction(one-way) channel, generally applied to receiver and sender respectively.
   195  // so there is stricter restriction on both sides to prevent misoperations(misuse).
   196  
   197  // random number based on channel, just for fun.
   198  func TestRandom(t *testing.T) {
   199  	random(100)
   200  }
   201  
   202  func random(n int) <-chan int {
   203  	c := make(chan int)
   204  	go func() {
   205  		defer close(c)
   206  		for i := 0; i < n; i++ {
   207  			select {
   208  			case c <- 0:
   209  			case c <- 1:
   210  			}
   211  		}
   212  	}()
   213  	return c
   214  }