rate: avoid creating timer in WaitN if delay is zero

name      old time/op    new time/op    delta
AllowN-4    76.7ns ± 6%    76.6ns ± 3%      ~     (p=0.897 n=10+10)
WaitNNoDelay-4     1.36µs ± 3%    0.10µs ± 1%   -92.64%  (p=0.000 n=10+9)

name      old alloc/op   new alloc/op   delta
AllowN-4     0.00B          0.00B           ~     (all equal)
WaitNNoDelay-4       208B ± 0%        0B       -100.00%  (p=0.000 n=10+10)

name      old allocs/op  new allocs/op  delta
AllowN-4      0.00           0.00           ~     (all equal)
WaitNNoDelay-4       3.00 ± 0%      0.00       -100.00%  (p=0.000 n=10+10)

Change-Id: I83addc3b3f7b053d6eee637fe188e21ca9b39f11
GitHub-Last-Rev: 2284b8e7b14d2f54870ddb80a40e8cf24996cd1f
GitHub-Pull-Request: golang/time#5
Reviewed-on: https://go-review.googlesource.com/106461
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/rate/rate.go b/rate/rate.go
index eabcd11..7228d97 100644
--- a/rate/rate.go
+++ b/rate/rate.go
@@ -253,8 +253,12 @@
 	if !r.ok {
 		return fmt.Errorf("rate: Wait(n=%d) would exceed context deadline", n)
 	}
-	// Wait
-	t := time.NewTimer(r.DelayFrom(now))
+	// Wait if necessary
+	delay := r.DelayFrom(now)
+	if delay == 0 {
+		return nil
+	}
+	t := time.NewTimer(delay)
 	defer t.Stop()
 	select {
 	case <-t.C:
diff --git a/rate/rate_test.go b/rate/rate_test.go
index e8add69..ec8c66d 100644
--- a/rate/rate_test.go
+++ b/rate/rate_test.go
@@ -447,3 +447,13 @@
 		}
 	})
 }
+
+func BenchmarkWaitNNoDelay(b *testing.B) {
+	lim := NewLimiter(Limit(b.N), b.N)
+	ctx := context.Background()
+	b.ReportAllocs()
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		lim.WaitN(ctx, 1)
+	}
+}