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 }