github.com/aloncn/graphics-go@v0.0.1/src/runtime/chan_test.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package runtime_test
     6  
     7  import (
     8  	"runtime"
     9  	"sync"
    10  	"sync/atomic"
    11  	"testing"
    12  	"time"
    13  )
    14  
    15  func TestChan(t *testing.T) {
    16  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
    17  	N := 200
    18  	if testing.Short() {
    19  		N = 20
    20  	}
    21  	for chanCap := 0; chanCap < N; chanCap++ {
    22  		{
    23  			// Ensure that receive from empty chan blocks.
    24  			c := make(chan int, chanCap)
    25  			recv1 := false
    26  			go func() {
    27  				_ = <-c
    28  				recv1 = true
    29  			}()
    30  			recv2 := false
    31  			go func() {
    32  				_, _ = <-c
    33  				recv2 = true
    34  			}()
    35  			time.Sleep(time.Millisecond)
    36  			if recv1 || recv2 {
    37  				t.Fatalf("chan[%d]: receive from empty chan", chanCap)
    38  			}
    39  			// Ensure that non-blocking receive does not block.
    40  			select {
    41  			case _ = <-c:
    42  				t.Fatalf("chan[%d]: receive from empty chan", chanCap)
    43  			default:
    44  			}
    45  			select {
    46  			case _, _ = <-c:
    47  				t.Fatalf("chan[%d]: receive from empty chan", chanCap)
    48  			default:
    49  			}
    50  			c <- 0
    51  			c <- 0
    52  		}
    53  
    54  		{
    55  			// Ensure that send to full chan blocks.
    56  			c := make(chan int, chanCap)
    57  			for i := 0; i < chanCap; i++ {
    58  				c <- i
    59  			}
    60  			sent := uint32(0)
    61  			go func() {
    62  				c <- 0
    63  				atomic.StoreUint32(&sent, 1)
    64  			}()
    65  			time.Sleep(time.Millisecond)
    66  			if atomic.LoadUint32(&sent) != 0 {
    67  				t.Fatalf("chan[%d]: send to full chan", chanCap)
    68  			}
    69  			// Ensure that non-blocking send does not block.
    70  			select {
    71  			case c <- 0:
    72  				t.Fatalf("chan[%d]: send to full chan", chanCap)
    73  			default:
    74  			}
    75  			<-c
    76  		}
    77  
    78  		{
    79  			// Ensure that we receive 0 from closed chan.
    80  			c := make(chan int, chanCap)
    81  			for i := 0; i < chanCap; i++ {
    82  				c <- i
    83  			}
    84  			close(c)
    85  			for i := 0; i < chanCap; i++ {
    86  				v := <-c
    87  				if v != i {
    88  					t.Fatalf("chan[%d]: received %v, expected %v", chanCap, v, i)
    89  				}
    90  			}
    91  			if v := <-c; v != 0 {
    92  				t.Fatalf("chan[%d]: received %v, expected %v", chanCap, v, 0)
    93  			}
    94  			if v, ok := <-c; v != 0 || ok {
    95  				t.Fatalf("chan[%d]: received %v/%v, expected %v/%v", chanCap, v, ok, 0, false)
    96  			}
    97  		}
    98  
    99  		{
   100  			// Ensure that close unblocks receive.
   101  			c := make(chan int, chanCap)
   102  			done := make(chan bool)
   103  			go func() {
   104  				v, ok := <-c
   105  				done <- v == 0 && ok == false
   106  			}()
   107  			time.Sleep(time.Millisecond)
   108  			close(c)
   109  			if !<-done {
   110  				t.Fatalf("chan[%d]: received non zero from closed chan", chanCap)
   111  			}
   112  		}
   113  
   114  		{
   115  			// Send 100 integers,
   116  			// ensure that we receive them non-corrupted in FIFO order.
   117  			c := make(chan int, chanCap)
   118  			go func() {
   119  				for i := 0; i < 100; i++ {
   120  					c <- i
   121  				}
   122  			}()
   123  			for i := 0; i < 100; i++ {
   124  				v := <-c
   125  				if v != i {
   126  					t.Fatalf("chan[%d]: received %v, expected %v", chanCap, v, i)
   127  				}
   128  			}
   129  
   130  			// Same, but using recv2.
   131  			go func() {
   132  				for i := 0; i < 100; i++ {
   133  					c <- i
   134  				}
   135  			}()
   136  			for i := 0; i < 100; i++ {
   137  				v, ok := <-c
   138  				if !ok {
   139  					t.Fatalf("chan[%d]: receive failed, expected %v", chanCap, i)
   140  				}
   141  				if v != i {
   142  					t.Fatalf("chan[%d]: received %v, expected %v", chanCap, v, i)
   143  				}
   144  			}
   145  
   146  			// Send 1000 integers in 4 goroutines,
   147  			// ensure that we receive what we send.
   148  			const P = 4
   149  			const L = 1000
   150  			for p := 0; p < P; p++ {
   151  				go func() {
   152  					for i := 0; i < L; i++ {
   153  						c <- i
   154  					}
   155  				}()
   156  			}
   157  			done := make(chan map[int]int)
   158  			for p := 0; p < P; p++ {
   159  				go func() {
   160  					recv := make(map[int]int)
   161  					for i := 0; i < L; i++ {
   162  						v := <-c
   163  						recv[v] = recv[v] + 1
   164  					}
   165  					done <- recv
   166  				}()
   167  			}
   168  			recv := make(map[int]int)
   169  			for p := 0; p < P; p++ {
   170  				for k, v := range <-done {
   171  					recv[k] = recv[k] + v
   172  				}
   173  			}
   174  			if len(recv) != L {
   175  				t.Fatalf("chan[%d]: received %v values, expected %v", chanCap, len(recv), L)
   176  			}
   177  			for _, v := range recv {
   178  				if v != P {
   179  					t.Fatalf("chan[%d]: received %v values, expected %v", chanCap, v, P)
   180  				}
   181  			}
   182  		}
   183  
   184  		{
   185  			// Test len/cap.
   186  			c := make(chan int, chanCap)
   187  			if len(c) != 0 || cap(c) != chanCap {
   188  				t.Fatalf("chan[%d]: bad len/cap, expect %v/%v, got %v/%v", chanCap, 0, chanCap, len(c), cap(c))
   189  			}
   190  			for i := 0; i < chanCap; i++ {
   191  				c <- i
   192  			}
   193  			if len(c) != chanCap || cap(c) != chanCap {
   194  				t.Fatalf("chan[%d]: bad len/cap, expect %v/%v, got %v/%v", chanCap, chanCap, chanCap, len(c), cap(c))
   195  			}
   196  		}
   197  
   198  	}
   199  }
   200  
   201  func TestNonblockRecvRace(t *testing.T) {
   202  	n := 10000
   203  	if testing.Short() {
   204  		n = 100
   205  	}
   206  	for i := 0; i < n; i++ {
   207  		c := make(chan int, 1)
   208  		c <- 1
   209  		go func() {
   210  			select {
   211  			case <-c:
   212  			default:
   213  				t.Fatal("chan is not ready")
   214  			}
   215  		}()
   216  		close(c)
   217  		<-c
   218  	}
   219  }
   220  
   221  // This test checks that select acts on the state of the channels at one
   222  // moment in the execution, not over a smeared time window.
   223  // In the test, one goroutine does:
   224  //	create c1, c2
   225  //	make c1 ready for receiving
   226  //	create second goroutine
   227  //	make c2 ready for receiving
   228  //	make c1 no longer ready for receiving (if possible)
   229  // The second goroutine does a non-blocking select receiving from c1 and c2.
   230  // From the time the second goroutine is created, at least one of c1 and c2
   231  // is always ready for receiving, so the select in the second goroutine must
   232  // always receive from one or the other. It must never execute the default case.
   233  func TestNonblockSelectRace(t *testing.T) {
   234  	n := 100000
   235  	if testing.Short() {
   236  		n = 1000
   237  	}
   238  	done := make(chan bool, 1)
   239  	for i := 0; i < n; i++ {
   240  		c1 := make(chan int, 1)
   241  		c2 := make(chan int, 1)
   242  		c1 <- 1
   243  		go func() {
   244  			select {
   245  			case <-c1:
   246  			case <-c2:
   247  			default:
   248  				done <- false
   249  				return
   250  			}
   251  			done <- true
   252  		}()
   253  		c2 <- 1
   254  		select {
   255  		case <-c1:
   256  		default:
   257  		}
   258  		if !<-done {
   259  			t.Fatal("no chan is ready")
   260  		}
   261  	}
   262  }
   263  
   264  // Same as TestNonblockSelectRace, but close(c2) replaces c2 <- 1.
   265  func TestNonblockSelectRace2(t *testing.T) {
   266  	n := 100000
   267  	if testing.Short() {
   268  		n = 1000
   269  	}
   270  	done := make(chan bool, 1)
   271  	for i := 0; i < n; i++ {
   272  		c1 := make(chan int, 1)
   273  		c2 := make(chan int)
   274  		c1 <- 1
   275  		go func() {
   276  			select {
   277  			case <-c1:
   278  			case <-c2:
   279  			default:
   280  				done <- false
   281  				return
   282  			}
   283  			done <- true
   284  		}()
   285  		close(c2)
   286  		select {
   287  		case <-c1:
   288  		default:
   289  		}
   290  		if !<-done {
   291  			t.Fatal("no chan is ready")
   292  		}
   293  	}
   294  }
   295  
   296  func TestSelfSelect(t *testing.T) {
   297  	// Ensure that send/recv on the same chan in select
   298  	// does not crash nor deadlock.
   299  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
   300  	for _, chanCap := range []int{0, 10} {
   301  		var wg sync.WaitGroup
   302  		wg.Add(2)
   303  		c := make(chan int, chanCap)
   304  		for p := 0; p < 2; p++ {
   305  			p := p
   306  			go func() {
   307  				defer wg.Done()
   308  				for i := 0; i < 1000; i++ {
   309  					if p == 0 || i%2 == 0 {
   310  						select {
   311  						case c <- p:
   312  						case v := <-c:
   313  							if chanCap == 0 && v == p {
   314  								t.Fatalf("self receive")
   315  							}
   316  						}
   317  					} else {
   318  						select {
   319  						case v := <-c:
   320  							if chanCap == 0 && v == p {
   321  								t.Fatalf("self receive")
   322  							}
   323  						case c <- p:
   324  						}
   325  					}
   326  				}
   327  			}()
   328  		}
   329  		wg.Wait()
   330  	}
   331  }
   332  
   333  func TestSelectStress(t *testing.T) {
   334  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(10))
   335  	var c [4]chan int
   336  	c[0] = make(chan int)
   337  	c[1] = make(chan int)
   338  	c[2] = make(chan int, 2)
   339  	c[3] = make(chan int, 3)
   340  	N := int(1e5)
   341  	if testing.Short() {
   342  		N /= 10
   343  	}
   344  	// There are 4 goroutines that send N values on each of the chans,
   345  	// + 4 goroutines that receive N values on each of the chans,
   346  	// + 1 goroutine that sends N values on each of the chans in a single select,
   347  	// + 1 goroutine that receives N values on each of the chans in a single select.
   348  	// All these sends, receives and selects interact chaotically at runtime,
   349  	// but we are careful that this whole construct does not deadlock.
   350  	var wg sync.WaitGroup
   351  	wg.Add(10)
   352  	for k := 0; k < 4; k++ {
   353  		k := k
   354  		go func() {
   355  			for i := 0; i < N; i++ {
   356  				c[k] <- 0
   357  			}
   358  			wg.Done()
   359  		}()
   360  		go func() {
   361  			for i := 0; i < N; i++ {
   362  				<-c[k]
   363  			}
   364  			wg.Done()
   365  		}()
   366  	}
   367  	go func() {
   368  		var n [4]int
   369  		c1 := c
   370  		for i := 0; i < 4*N; i++ {
   371  			select {
   372  			case c1[3] <- 0:
   373  				n[3]++
   374  				if n[3] == N {
   375  					c1[3] = nil
   376  				}
   377  			case c1[2] <- 0:
   378  				n[2]++
   379  				if n[2] == N {
   380  					c1[2] = nil
   381  				}
   382  			case c1[0] <- 0:
   383  				n[0]++
   384  				if n[0] == N {
   385  					c1[0] = nil
   386  				}
   387  			case c1[1] <- 0:
   388  				n[1]++
   389  				if n[1] == N {
   390  					c1[1] = nil
   391  				}
   392  			}
   393  		}
   394  		wg.Done()
   395  	}()
   396  	go func() {
   397  		var n [4]int
   398  		c1 := c
   399  		for i := 0; i < 4*N; i++ {
   400  			select {
   401  			case <-c1[0]:
   402  				n[0]++
   403  				if n[0] == N {
   404  					c1[0] = nil
   405  				}
   406  			case <-c1[1]:
   407  				n[1]++
   408  				if n[1] == N {
   409  					c1[1] = nil
   410  				}
   411  			case <-c1[2]:
   412  				n[2]++
   413  				if n[2] == N {
   414  					c1[2] = nil
   415  				}
   416  			case <-c1[3]:
   417  				n[3]++
   418  				if n[3] == N {
   419  					c1[3] = nil
   420  				}
   421  			}
   422  		}
   423  		wg.Done()
   424  	}()
   425  	wg.Wait()
   426  }
   427  
   428  func TestChanSendInterface(t *testing.T) {
   429  	type mt struct{}
   430  	m := &mt{}
   431  	c := make(chan interface{}, 1)
   432  	c <- m
   433  	select {
   434  	case c <- m:
   435  	default:
   436  	}
   437  	select {
   438  	case c <- m:
   439  	case c <- &mt{}:
   440  	default:
   441  	}
   442  }
   443  
   444  func TestPseudoRandomSend(t *testing.T) {
   445  	n := 100
   446  	for _, chanCap := range []int{0, n} {
   447  		c := make(chan int, chanCap)
   448  		l := make([]int, n)
   449  		var m sync.Mutex
   450  		m.Lock()
   451  		go func() {
   452  			for i := 0; i < n; i++ {
   453  				runtime.Gosched()
   454  				l[i] = <-c
   455  			}
   456  			m.Unlock()
   457  		}()
   458  		for i := 0; i < n; i++ {
   459  			select {
   460  			case c <- 1:
   461  			case c <- 0:
   462  			}
   463  		}
   464  		m.Lock() // wait
   465  		n0 := 0
   466  		n1 := 0
   467  		for _, i := range l {
   468  			n0 += (i + 1) % 2
   469  			n1 += i
   470  		}
   471  		if n0 <= n/10 || n1 <= n/10 {
   472  			t.Errorf("Want pseudorandom, got %d zeros and %d ones (chan cap %d)", n0, n1, chanCap)
   473  		}
   474  	}
   475  }
   476  
   477  func TestMultiConsumer(t *testing.T) {
   478  	const nwork = 23
   479  	const niter = 271828
   480  
   481  	pn := []int{2, 3, 7, 11, 13, 17, 19, 23, 27, 31}
   482  
   483  	q := make(chan int, nwork*3)
   484  	r := make(chan int, nwork*3)
   485  
   486  	// workers
   487  	var wg sync.WaitGroup
   488  	for i := 0; i < nwork; i++ {
   489  		wg.Add(1)
   490  		go func(w int) {
   491  			for v := range q {
   492  				// mess with the fifo-ish nature of range
   493  				if pn[w%len(pn)] == v {
   494  					runtime.Gosched()
   495  				}
   496  				r <- v
   497  			}
   498  			wg.Done()
   499  		}(i)
   500  	}
   501  
   502  	// feeder & closer
   503  	expect := 0
   504  	go func() {
   505  		for i := 0; i < niter; i++ {
   506  			v := pn[i%len(pn)]
   507  			expect += v
   508  			q <- v
   509  		}
   510  		close(q)  // no more work
   511  		wg.Wait() // workers done
   512  		close(r)  // ... so there can be no more results
   513  	}()
   514  
   515  	// consume & check
   516  	n := 0
   517  	s := 0
   518  	for v := range r {
   519  		n++
   520  		s += v
   521  	}
   522  	if n != niter || s != expect {
   523  		t.Errorf("Expected sum %d (got %d) from %d iter (saw %d)",
   524  			expect, s, niter, n)
   525  	}
   526  }
   527  
   528  func TestShrinkStackDuringBlockedSend(t *testing.T) {
   529  	// make sure that channel operations still work when we are
   530  	// blocked on a channel send and we shrink the stack.
   531  	// NOTE: this test probably won't fail unless stack1.go:stackDebug
   532  	// is set to >= 1.
   533  	const n = 10
   534  	c := make(chan int)
   535  	done := make(chan struct{})
   536  
   537  	go func() {
   538  		for i := 0; i < n; i++ {
   539  			c <- i
   540  			// use lots of stack, briefly.
   541  			stackGrowthRecursive(20)
   542  		}
   543  		done <- struct{}{}
   544  	}()
   545  
   546  	for i := 0; i < n; i++ {
   547  		x := <-c
   548  		if x != i {
   549  			t.Errorf("bad channel read: want %d, got %d", i, x)
   550  		}
   551  		// Waste some time so sender can finish using lots of stack
   552  		// and block in channel send.
   553  		time.Sleep(1 * time.Millisecond)
   554  		// trigger GC which will shrink the stack of the sender.
   555  		runtime.GC()
   556  	}
   557  	<-done
   558  }
   559  
   560  func TestSelectDuplicateChannel(t *testing.T) {
   561  	// This test makes sure we can queue a G on
   562  	// the same channel multiple times.
   563  	c := make(chan int)
   564  	d := make(chan int)
   565  	e := make(chan int)
   566  
   567  	// goroutine A
   568  	go func() {
   569  		select {
   570  		case <-c:
   571  		case <-c:
   572  		case <-d:
   573  		}
   574  		e <- 9
   575  	}()
   576  	time.Sleep(time.Millisecond) // make sure goroutine A gets qeueued first on c
   577  
   578  	// goroutine B
   579  	go func() {
   580  		<-c
   581  	}()
   582  	time.Sleep(time.Millisecond) // make sure goroutine B gets queued on c before continuing
   583  
   584  	d <- 7 // wake up A, it dequeues itself from c.  This operation used to corrupt c.recvq.
   585  	<-e    // A tells us it's done
   586  	c <- 8 // wake up B.  This operation used to fail because c.recvq was corrupted (it tries to wake up an already running G instead of B)
   587  }
   588  
   589  func BenchmarkChanNonblocking(b *testing.B) {
   590  	myc := make(chan int)
   591  	b.RunParallel(func(pb *testing.PB) {
   592  		for pb.Next() {
   593  			select {
   594  			case <-myc:
   595  			default:
   596  			}
   597  		}
   598  	})
   599  }
   600  
   601  func BenchmarkSelectUncontended(b *testing.B) {
   602  	b.RunParallel(func(pb *testing.PB) {
   603  		myc1 := make(chan int, 1)
   604  		myc2 := make(chan int, 1)
   605  		myc1 <- 0
   606  		for pb.Next() {
   607  			select {
   608  			case <-myc1:
   609  				myc2 <- 0
   610  			case <-myc2:
   611  				myc1 <- 0
   612  			}
   613  		}
   614  	})
   615  }
   616  
   617  func BenchmarkSelectSyncContended(b *testing.B) {
   618  	myc1 := make(chan int)
   619  	myc2 := make(chan int)
   620  	myc3 := make(chan int)
   621  	done := make(chan int)
   622  	b.RunParallel(func(pb *testing.PB) {
   623  		go func() {
   624  			for {
   625  				select {
   626  				case myc1 <- 0:
   627  				case myc2 <- 0:
   628  				case myc3 <- 0:
   629  				case <-done:
   630  					return
   631  				}
   632  			}
   633  		}()
   634  		for pb.Next() {
   635  			select {
   636  			case <-myc1:
   637  			case <-myc2:
   638  			case <-myc3:
   639  			}
   640  		}
   641  	})
   642  	close(done)
   643  }
   644  
   645  func BenchmarkSelectAsyncContended(b *testing.B) {
   646  	procs := runtime.GOMAXPROCS(0)
   647  	myc1 := make(chan int, procs)
   648  	myc2 := make(chan int, procs)
   649  	b.RunParallel(func(pb *testing.PB) {
   650  		myc1 <- 0
   651  		for pb.Next() {
   652  			select {
   653  			case <-myc1:
   654  				myc2 <- 0
   655  			case <-myc2:
   656  				myc1 <- 0
   657  			}
   658  		}
   659  	})
   660  }
   661  
   662  func BenchmarkSelectNonblock(b *testing.B) {
   663  	myc1 := make(chan int)
   664  	myc2 := make(chan int)
   665  	myc3 := make(chan int, 1)
   666  	myc4 := make(chan int, 1)
   667  	b.RunParallel(func(pb *testing.PB) {
   668  		for pb.Next() {
   669  			select {
   670  			case <-myc1:
   671  			default:
   672  			}
   673  			select {
   674  			case myc2 <- 0:
   675  			default:
   676  			}
   677  			select {
   678  			case <-myc3:
   679  			default:
   680  			}
   681  			select {
   682  			case myc4 <- 0:
   683  			default:
   684  			}
   685  		}
   686  	})
   687  }
   688  
   689  func BenchmarkChanUncontended(b *testing.B) {
   690  	const C = 100
   691  	b.RunParallel(func(pb *testing.PB) {
   692  		myc := make(chan int, C)
   693  		for pb.Next() {
   694  			for i := 0; i < C; i++ {
   695  				myc <- 0
   696  			}
   697  			for i := 0; i < C; i++ {
   698  				<-myc
   699  			}
   700  		}
   701  	})
   702  }
   703  
   704  func BenchmarkChanContended(b *testing.B) {
   705  	const C = 100
   706  	myc := make(chan int, C*runtime.GOMAXPROCS(0))
   707  	b.RunParallel(func(pb *testing.PB) {
   708  		for pb.Next() {
   709  			for i := 0; i < C; i++ {
   710  				myc <- 0
   711  			}
   712  			for i := 0; i < C; i++ {
   713  				<-myc
   714  			}
   715  		}
   716  	})
   717  }
   718  
   719  func BenchmarkChanSync(b *testing.B) {
   720  	const CallsPerSched = 1000
   721  	procs := 2
   722  	N := int32(b.N / CallsPerSched / procs * procs)
   723  	c := make(chan bool, procs)
   724  	myc := make(chan int)
   725  	for p := 0; p < procs; p++ {
   726  		go func() {
   727  			for {
   728  				i := atomic.AddInt32(&N, -1)
   729  				if i < 0 {
   730  					break
   731  				}
   732  				for g := 0; g < CallsPerSched; g++ {
   733  					if i%2 == 0 {
   734  						<-myc
   735  						myc <- 0
   736  					} else {
   737  						myc <- 0
   738  						<-myc
   739  					}
   740  				}
   741  			}
   742  			c <- true
   743  		}()
   744  	}
   745  	for p := 0; p < procs; p++ {
   746  		<-c
   747  	}
   748  }
   749  
   750  func benchmarkChanProdCons(b *testing.B, chanSize, localWork int) {
   751  	const CallsPerSched = 1000
   752  	procs := runtime.GOMAXPROCS(-1)
   753  	N := int32(b.N / CallsPerSched)
   754  	c := make(chan bool, 2*procs)
   755  	myc := make(chan int, chanSize)
   756  	for p := 0; p < procs; p++ {
   757  		go func() {
   758  			foo := 0
   759  			for atomic.AddInt32(&N, -1) >= 0 {
   760  				for g := 0; g < CallsPerSched; g++ {
   761  					for i := 0; i < localWork; i++ {
   762  						foo *= 2
   763  						foo /= 2
   764  					}
   765  					myc <- 1
   766  				}
   767  			}
   768  			myc <- 0
   769  			c <- foo == 42
   770  		}()
   771  		go func() {
   772  			foo := 0
   773  			for {
   774  				v := <-myc
   775  				if v == 0 {
   776  					break
   777  				}
   778  				for i := 0; i < localWork; i++ {
   779  					foo *= 2
   780  					foo /= 2
   781  				}
   782  			}
   783  			c <- foo == 42
   784  		}()
   785  	}
   786  	for p := 0; p < procs; p++ {
   787  		<-c
   788  		<-c
   789  	}
   790  }
   791  
   792  func BenchmarkChanProdCons0(b *testing.B) {
   793  	benchmarkChanProdCons(b, 0, 0)
   794  }
   795  
   796  func BenchmarkChanProdCons10(b *testing.B) {
   797  	benchmarkChanProdCons(b, 10, 0)
   798  }
   799  
   800  func BenchmarkChanProdCons100(b *testing.B) {
   801  	benchmarkChanProdCons(b, 100, 0)
   802  }
   803  
   804  func BenchmarkChanProdConsWork0(b *testing.B) {
   805  	benchmarkChanProdCons(b, 0, 100)
   806  }
   807  
   808  func BenchmarkChanProdConsWork10(b *testing.B) {
   809  	benchmarkChanProdCons(b, 10, 100)
   810  }
   811  
   812  func BenchmarkChanProdConsWork100(b *testing.B) {
   813  	benchmarkChanProdCons(b, 100, 100)
   814  }
   815  
   816  func BenchmarkSelectProdCons(b *testing.B) {
   817  	const CallsPerSched = 1000
   818  	procs := runtime.GOMAXPROCS(-1)
   819  	N := int32(b.N / CallsPerSched)
   820  	c := make(chan bool, 2*procs)
   821  	myc := make(chan int, 128)
   822  	myclose := make(chan bool)
   823  	for p := 0; p < procs; p++ {
   824  		go func() {
   825  			// Producer: sends to myc.
   826  			foo := 0
   827  			// Intended to not fire during benchmarking.
   828  			mytimer := time.After(time.Hour)
   829  			for atomic.AddInt32(&N, -1) >= 0 {
   830  				for g := 0; g < CallsPerSched; g++ {
   831  					// Model some local work.
   832  					for i := 0; i < 100; i++ {
   833  						foo *= 2
   834  						foo /= 2
   835  					}
   836  					select {
   837  					case myc <- 1:
   838  					case <-mytimer:
   839  					case <-myclose:
   840  					}
   841  				}
   842  			}
   843  			myc <- 0
   844  			c <- foo == 42
   845  		}()
   846  		go func() {
   847  			// Consumer: receives from myc.
   848  			foo := 0
   849  			// Intended to not fire during benchmarking.
   850  			mytimer := time.After(time.Hour)
   851  		loop:
   852  			for {
   853  				select {
   854  				case v := <-myc:
   855  					if v == 0 {
   856  						break loop
   857  					}
   858  				case <-mytimer:
   859  				case <-myclose:
   860  				}
   861  				// Model some local work.
   862  				for i := 0; i < 100; i++ {
   863  					foo *= 2
   864  					foo /= 2
   865  				}
   866  			}
   867  			c <- foo == 42
   868  		}()
   869  	}
   870  	for p := 0; p < procs; p++ {
   871  		<-c
   872  		<-c
   873  	}
   874  }
   875  
   876  func BenchmarkChanCreation(b *testing.B) {
   877  	b.RunParallel(func(pb *testing.PB) {
   878  		for pb.Next() {
   879  			myc := make(chan int, 1)
   880  			myc <- 0
   881  			<-myc
   882  		}
   883  	})
   884  }
   885  
   886  func BenchmarkChanSem(b *testing.B) {
   887  	type Empty struct{}
   888  	myc := make(chan Empty, runtime.GOMAXPROCS(0))
   889  	b.RunParallel(func(pb *testing.PB) {
   890  		for pb.Next() {
   891  			myc <- Empty{}
   892  			<-myc
   893  		}
   894  	})
   895  }
   896  
   897  func BenchmarkChanPopular(b *testing.B) {
   898  	const n = 1000
   899  	c := make(chan bool)
   900  	var a []chan bool
   901  	var wg sync.WaitGroup
   902  	wg.Add(n)
   903  	for j := 0; j < n; j++ {
   904  		d := make(chan bool)
   905  		a = append(a, d)
   906  		go func() {
   907  			for i := 0; i < b.N; i++ {
   908  				select {
   909  				case <-c:
   910  				case <-d:
   911  				}
   912  			}
   913  			wg.Done()
   914  		}()
   915  	}
   916  	for i := 0; i < b.N; i++ {
   917  		for _, d := range a {
   918  			d <- true
   919  		}
   920  	}
   921  	wg.Wait()
   922  }