func TestPull(t *testing.T) {
        for end := 0; end <= 3; end++ {
                t.Run(fmt.Sprint(end), func(t *testing.T) {
-                       ng := runtime.NumGoroutine()
+                       ng := stableNumGoroutine()
                        wantNG := func(want int) {
                                if xg := runtime.NumGoroutine() - ng; xg != want {
                                        t.Helper()
 func TestPull2(t *testing.T) {
        for end := 0; end <= 3; end++ {
                t.Run(fmt.Sprint(end), func(t *testing.T) {
-                       ng := runtime.NumGoroutine()
+                       ng := stableNumGoroutine()
                        wantNG := func(want int) {
                                if xg := runtime.NumGoroutine() - ng; xg != want {
                                        t.Helper()
        }
 }
 
+// stableNumGoroutine is like NumGoroutine but tries to ensure stability of
+// the value by letting any exiting goroutines finish exiting.
+func stableNumGoroutine() int {
+       // The idea behind stablizing the value of NumGoroutine is to
+       // see the same value enough times in a row in between calls to
+       // runtime.Gosched. With GOMAXPROCS=1, we're trying to make sure
+       // that other goroutines run, so that they reach a stable point.
+       // It's not guaranteed, because it is still possible for a goroutine
+       // to Gosched back into itself, so we require NumGoroutine to be
+       // the same 100 times in a row. This should be more than enough to
+       // ensure all goroutines get a chance to run to completion (or to
+       // some block point) for a small group of test goroutines.
+       defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
+
+       c := 0
+       ng := runtime.NumGoroutine()
+       for i := 0; i < 1000; i++ {
+               nng := runtime.NumGoroutine()
+               if nng == ng {
+                       c++
+               } else {
+                       c = 0
+                       ng = nng
+               }
+               if c >= 100 {
+                       // The same value 100 times in a row is good enough.
+                       return ng
+               }
+               runtime.Gosched()
+       }
+       panic("failed to stabilize NumGoroutine after 1000 iterations")
+}
+
 func TestPullDoubleNext(t *testing.T) {
        next, _ := Pull(doDoubleNext())
        nextSlot = next