英文:
What is the effects for this empty select-case-default code block?
问题
我正在尝试理解一个池库的代码,当实例化一个池结构体时,调用一个名为startCleanerLocked(t Duration)
的函数,在这个函数中,有一个空的select...case...default...
代码块,我无法理解这个代码块的作用。
Pool
接口定义如下:
// Pool接口。
type Pool interface {
Get(ctx context.Context) (io.Closer, error)
Put(ctx context.Context, c io.Closer, forceClose bool) error
Close() error
}
List
结构体实现了Pool
接口,定义如下:
type List struct {
// New是一个由应用程序提供的用于创建和配置项目的函数。
//
// 从new返回的项目不能处于特殊状态
// (订阅了pubsub频道,启动了事务等)。
New func(ctx context.Context) (io.Closer, error)
// mu保护下面定义的字段。
mu sync.Mutex
cond chan struct{}
closed bool
active int
// 清理过期项目
cleanerCh chan struct{}
// 最近使用的项目堆栈,最近使用的项目在前面。
idles list.List
// Config池配置
conf *Config
}
当创建一个新的池时,会调用startCleanerLocked(t Duration)
函数:
// NewList创建一个新的池。
func NewList(c *Config) *List {
// 检查配置
if c == nil || c.Active < c.Idle {
panic("config nil or Idle Must <= Active")
}
// 创建池
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 {
// 如果设置为0,staleCleaner()将直接返回
return
}
if d < time.Duration(p.conf.IdleTimeout) && p.cleanerCh != nil {
select {
case p.cleanerCh <- struct{}{}:
default:
}
}
// 只运行一次,清理过期项目。
if p.cleanerCh == nil {
p.cleanerCh = make(chan struct{}, 1)
go p.staleCleaner()
}
}
这个代码块的作用是什么:
select {
case p.cleanerCh <- struct{}{}:
default:
}
看起来它似乎没有什么作用...
在staleCleaner()
函数中,也有一个相同的空的select...case...case
,同样无法理解其作用:
// staleCleaner清理过期项目的处理。
func (p *List) staleCleaner() {
ticker := time.NewTicker(100 * time.Millisecond)
for {
select {
case <-ticker.C:
case <-p.cleanerCh: // maxLifetime被更改或数据库被关闭。
}
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 {
// 不可能发生
break
}
ic := e.Value.(item)
if !ic.expired(time.Duration(p.conf.IdleTimeout)) {
// 不需要继续。
break
}
p.idles.Remove(e)
p.release()
p.mu.Unlock()
ic.c.Close()
p.mu.Lock()
}
p.mu.Unlock()
}
}
英文:
I'm trying to understand a pool library codes, and when instancing a pool struct, call a function named startCleanerLocked(t Duration)
, in this function, there's one empty select...case...default...
code block, I cann't understand what is the effect for this code block.
Pool Interface
is:
// 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
implement 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
}
when Create a new pool, startCleanerLocked(t Duration)
function be called:
// 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
}
and in startCleanerLocked(t Duration)
, there is a 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()
}
}
what's the effect for this code block:
select {
case p.cleanerCh <- struct{}{}:
default:
}
Seems it's nothing to do...
and in staleCleaner()
, there is a same empty select..case...case
, also cannot undestand its effect:
// 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()
}
}
答案1
得分: 0
select {
case p.cleanerCh <- struct{}{}:
default:
}
这是一个非阻塞的 select
语句(因为有一个 default:
分支)。
如果 p.cleanerCh
通道的另一端有一个接收器 goroutine,也就是说有一个 goroutine 正在等待接收操作 <-p.cleanerCh
,那么 case p.cleanerCh <- struct{}{}
会立即执行,从而解除接收操作 <-p.cleanerCh
的阻塞,然后 goroutine 可以继续执行后续的语句。
如果没有接收器 goroutine,那么 default:
分支会立即执行,startCleanerLocked
函数可以继续执行 select
语句后面的语句。
select {
case <-ticker.C:
case <-p.cleanerCh: // maxLifetime was changed or db was closed.
}
这是一个阻塞的 select
语句(因为没有 default:
分支)。
这个 select
语句会阻塞 for
循环,直到两个通信分支中的一个准备好接收数据。
英文:
select {
case p.cleanerCh <- struct{}{}:
default:
}
This is a non-blocking select
statement. (because there is a default:
case)
If there is a receiver goroutine at the other end of the p.cleanerCh
channel, i.e. there is a goroutine that's currently "waiting" at a receive operation i.e. <-p.cleanerCh
, then the case p.cleanerCh <- struct{}{}
is executed immediately which effectively unblocks the receive operation <-p.cleanerCh
and then the goroutine can proceed to execute whatever statements follow.
If there is no receiver goroutine then the default:
case is immediately executed and the surrounding startCleanerLocked
function can proceed to execute whatever statement follow the select
statement.
select {
case <-ticker.C:
case <-p.cleanerCh: // maxLifetime was changed or db was closed.
}
This is a blocking select
statement. (because there is no default:
case)
This select
statement blocks the for
loop until one of the two communication cases is ready to receive.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论