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:
parent
a362d54614
commit
ca7c6ef33d
@ -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 {
|
||||
|
@ -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() {
|
||||
|
Loading…
Reference in New Issue
Block a user