这个空的 select-case-default 代码块有什么影响?
What is the effects for this empty select-case-default code block?
我试图理解一个池库代码,当实例化一个池结构时,调用一个名为 startCleanerLocked(t Duration)
的函数,在这个函数中,有一个空的 select...case...default...
代码块,我不能'了解此代码块的效果。
Pool Interface
是:
// Pool interface.
type Pool interface {
Get(ctx context.Context) (io.Closer, error)
Put(ctx context.Context, c io.Closer, forceClose bool) error
Close() error
}
List Struct
执行 Pool Interface
,
type List struct {
// New is an application supplied function for creating and configuring a
// item.
//
// The item returned from new must not be in a special state
// (subscribed to pubsub channel, transaction started, ...).
New func(ctx context.Context) (io.Closer, error)
// mu protects fields defined below.
mu sync.Mutex
cond chan struct{}
closed bool
active int
// clean stale items
cleanerCh chan struct{}
// Stack of item with most recently used at the front.
idles list.List
// Config pool configuration
conf *Config
}
当创建一个新池时,startCleanerLocked(t Duration)
函数被调用:
// NewList creates a new pool.
func NewList(c *Config) *List {
// check Config
if c == nil || c.Active < c.Idle {
panic("config nil or Idle Must <= Active")
}
// new pool
p := &List{conf: c}
p.cond = make(chan struct{})
p.startCleanerLocked(time.Duration(c.IdleTimeout))
return p
}
并且在startCleanerLocked(t Duration)
中,有一个select...case...default
:
// startCleanerLocked
func (p *List) startCleanerLocked(d time.Duration) {
if d <= 0 {
// if set 0, staleCleaner() will return directly
return
}
if d < time.Duration(p.conf.IdleTimeout) && p.cleanerCh != nil {
select {
case p.cleanerCh <- struct{}{}:
default:
}
}
// run only one, clean stale items.
if p.cleanerCh == nil {
p.cleanerCh = make(chan struct{}, 1)
go p.staleCleaner()
}
}
此代码块的作用是什么:
select {
case p.cleanerCh <- struct{}{}:
default:
}
好像没什么事...
和staleCleaner()
中一样,有一个空select..case...case
,同样无法理解其作用:
// staleCleaner clean stale items proc.
func (p *List) staleCleaner() {
ticker := time.NewTicker(100 * time.Millisecond)
for {
select {
case <-ticker.C:
case <-p.cleanerCh: // maxLifetime was changed or db was closed.
}
p.mu.Lock()
if p.closed || p.conf.IdleTimeout <= 0 {
p.mu.Unlock()
return
}
for i, n := 0, p.idles.Len(); i < n; i++ {
e := p.idles.Back()
if e == nil {
// no possible
break
}
ic := e.Value.(item)
if !ic.expired(time.Duration(p.conf.IdleTimeout)) {
// not need continue.
break
}
p.idles.Remove(e)
p.release()
p.mu.Unlock()
ic.c.Close()
p.mu.Lock()
}
p.mu.Unlock()
}
}
select {
case p.cleanerCh <- struct{}{}:
default:
}
这是一个non-blockingselect
声明。 (因为有default:
个案例)
如果 p.cleanerCh
通道的另一端有一个接收 goroutine,即有一个 goroutine 当前正在“等待”接收操作,即 <-p.cleanerCh
,那么 case p.cleanerCh <- struct{}{}
立即执行,这有效地解除了接收操作 <-p.cleanerCh
的阻塞,然后 goroutine 可以继续执行后面的任何语句。
如果没有receiver goroutine那么default:
case会被立即执行并且周围的startCleanerLocked
函数可以继续执行select
语句之后的任何语句。
select {
case <-ticker.C:
case <-p.cleanerCh: // maxLifetime was changed or db was closed.
}
这是一个阻塞语句 select
。 (因为没有default:
个案例)
此 select
语句阻塞 for
循环,直到两个通信案例之一准备好接收。
我试图理解一个池库代码,当实例化一个池结构时,调用一个名为 startCleanerLocked(t Duration)
的函数,在这个函数中,有一个空的 select...case...default...
代码块,我不能'了解此代码块的效果。
Pool Interface
是:
// Pool interface.
type Pool interface {
Get(ctx context.Context) (io.Closer, error)
Put(ctx context.Context, c io.Closer, forceClose bool) error
Close() error
}
List Struct
执行 Pool Interface
,
type List struct {
// New is an application supplied function for creating and configuring a
// item.
//
// The item returned from new must not be in a special state
// (subscribed to pubsub channel, transaction started, ...).
New func(ctx context.Context) (io.Closer, error)
// mu protects fields defined below.
mu sync.Mutex
cond chan struct{}
closed bool
active int
// clean stale items
cleanerCh chan struct{}
// Stack of item with most recently used at the front.
idles list.List
// Config pool configuration
conf *Config
}
当创建一个新池时,startCleanerLocked(t Duration)
函数被调用:
// NewList creates a new pool.
func NewList(c *Config) *List {
// check Config
if c == nil || c.Active < c.Idle {
panic("config nil or Idle Must <= Active")
}
// new pool
p := &List{conf: c}
p.cond = make(chan struct{})
p.startCleanerLocked(time.Duration(c.IdleTimeout))
return p
}
并且在startCleanerLocked(t Duration)
中,有一个select...case...default
:
// startCleanerLocked
func (p *List) startCleanerLocked(d time.Duration) {
if d <= 0 {
// if set 0, staleCleaner() will return directly
return
}
if d < time.Duration(p.conf.IdleTimeout) && p.cleanerCh != nil {
select {
case p.cleanerCh <- struct{}{}:
default:
}
}
// run only one, clean stale items.
if p.cleanerCh == nil {
p.cleanerCh = make(chan struct{}, 1)
go p.staleCleaner()
}
}
此代码块的作用是什么:
select {
case p.cleanerCh <- struct{}{}:
default:
}
好像没什么事...
和staleCleaner()
中一样,有一个空select..case...case
,同样无法理解其作用:
// staleCleaner clean stale items proc.
func (p *List) staleCleaner() {
ticker := time.NewTicker(100 * time.Millisecond)
for {
select {
case <-ticker.C:
case <-p.cleanerCh: // maxLifetime was changed or db was closed.
}
p.mu.Lock()
if p.closed || p.conf.IdleTimeout <= 0 {
p.mu.Unlock()
return
}
for i, n := 0, p.idles.Len(); i < n; i++ {
e := p.idles.Back()
if e == nil {
// no possible
break
}
ic := e.Value.(item)
if !ic.expired(time.Duration(p.conf.IdleTimeout)) {
// not need continue.
break
}
p.idles.Remove(e)
p.release()
p.mu.Unlock()
ic.c.Close()
p.mu.Lock()
}
p.mu.Unlock()
}
}
select {
case p.cleanerCh <- struct{}{}:
default:
}
这是一个non-blockingselect
声明。 (因为有default:
个案例)
如果 p.cleanerCh
通道的另一端有一个接收 goroutine,即有一个 goroutine 当前正在“等待”接收操作,即 <-p.cleanerCh
,那么 case p.cleanerCh <- struct{}{}
立即执行,这有效地解除了接收操作 <-p.cleanerCh
的阻塞,然后 goroutine 可以继续执行后面的任何语句。
如果没有receiver goroutine那么default:
case会被立即执行并且周围的startCleanerLocked
函数可以继续执行select
语句之后的任何语句。
select {
case <-ticker.C:
case <-p.cleanerCh: // maxLifetime was changed or db was closed.
}
这是一个阻塞语句 select
。 (因为没有default:
个案例)
此 select
语句阻塞 for
循环,直到两个通信案例之一准备好接收。