1
0
mirror of https://github.com/golang/go synced 2024-11-24 07:00:13 -07:00

runtime/chan.go: improve closed channel receive performance

Use this benchmark ut:

```go
func BenchmarkReceiveDataFromClosedChan(b *testing.B) {
	count := b.N
	ch := make(chan struct{}, count)
	for i := 0; i < count; i++ {
		ch <- struct{}{}
	}

	b.ResetTimer()
	for range ch {
	}
}
```

Benchmark 10 times(`go test -bench=.`), and then use `benchstat` got the result:

```shell
name                         old time/op  new time/op  delta
ReceiveDataFromClosedChan-5  12.0ns ± 1%  11.4ns ± 0%  -5.54%  (p=0.000 n=10+8)
```

Fixes:  #52067

Change-Id: I8db398cc8c04a46cb66ffb6768ab72a87903812f
GitHub-Last-Rev: 1e0142416f
GitHub-Pull-Request: golang/go#52068
Reviewed-on: https://go-review.googlesource.com/c/go/+/396884
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
Reviewed-by: Keith Randall <khr@google.com>
Run-TryBot: Keith Randall <khr@google.com>
Auto-Submit: Keith Randall <khr@google.com>
This commit is contained in:
champly 2022-04-12 01:54:45 +00:00 committed by Keith Randall
parent a362d54614
commit ca7c6ef33d
2 changed files with 33 additions and 16 deletions

View File

@ -510,24 +510,28 @@ func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool)
lock(&c.lock)
if c.closed != 0 && c.qcount == 0 {
if raceenabled {
raceacquire(c.raceaddr())
if c.closed != 0 {
if c.qcount == 0 {
if raceenabled {
raceacquire(c.raceaddr())
}
unlock(&c.lock)
if ep != nil {
typedmemclr(c.elemtype, ep)
}
return true, false
}
unlock(&c.lock)
if ep != nil {
typedmemclr(c.elemtype, ep)
// The channel has been closed, but the channel's buffer have data.
} else {
// Just found waiting sender with not closed.
if sg := c.sendq.dequeue(); sg != nil {
// Found a waiting sender. If buffer is size 0, receive value
// directly from sender. Otherwise, receive from head of queue
// and add sender's value to the tail of the queue (both map to
// the same buffer slot because the queue is full).
recv(c, sg, ep, func() { unlock(&c.lock) }, 3)
return true, true
}
return true, false
}
if sg := c.sendq.dequeue(); sg != nil {
// Found a waiting sender. If buffer is size 0, receive value
// directly from sender. Otherwise, receive from head of queue
// and add sender's value to the tail of the queue (both map to
// the same buffer slot because the queue is full).
recv(c, sg, ep, func() { unlock(&c.lock) }, 3)
return true, true
}
if c.qcount > 0 {

View File

@ -1127,6 +1127,19 @@ func BenchmarkSelectProdCons(b *testing.B) {
}
}
func BenchmarkReceiveDataFromClosedChan(b *testing.B) {
count := b.N
ch := make(chan struct{}, count)
for i := 0; i < count; i++ {
ch <- struct{}{}
}
close(ch)
b.ResetTimer()
for range ch {
}
}
func BenchmarkChanCreation(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {