详解Golang如何监听某个函数的开始执行和执行结束
作者:vistart
这篇文章主要为大家详细介绍了Golang如何监听某个函数的开始执行和执行结束,文中的示例代码讲解详细,有需要的小伙伴可以参考一下
如果想监听函数(方法)开始执行和执行结束,你需要设置两个通道:
- chanStarted: 用于发送开始执行信号。
- chanFinished: 用于发送执行结束信号。
同时,为了保证监听方能实时得知“开始执行”或“执行结束”信号,需要在执行任务前开启监听。
以下为模拟监听函数(方法)开始执行和执行结束的示例:
package main import ( "context" "fmt" "time" ) type Transit struct { worker func(ctx context.Context, a ...any) (any, error) chanStarted chan struct{} chanFinished chan struct{} } func (t *Transit) Run(ctx context.Context, a ...any) (any, error) { defer func() { t.chanFinished <- struct{}{} }() t.chanStarted <- struct{}{} return t.worker(ctx, a...) } func worker(ctx context.Context, a ...any) (any, error) { if timer, ok := a[0].(int); ok && timer > 0 { time.Sleep(time.Duration(timer) * time.Second) } return a[0], nil } func NewTransit() *Transit { return &Transit{ worker: worker, chanStarted: make(chan struct{}), chanFinished: make(chan struct{}), } } func main() { transit := NewTransit() chanStarted := transit.chanStarted chanFinished := transit.chanFinished finished := make(chan struct{}) go func() { for { select { case <-chanStarted: fmt.Println(time.Now(), "started.") case <-chanFinished: fmt.Println(time.Now(), "finished,") finished <- struct{}{} return default: } } }() run, _ := transit.Run(context.Background(), 0) <-finished fmt.Println(time.Now(), "result:", run) }
上述方案中,必须设置监听方,否则Run()
方法中会触发死锁。
如果想无阻塞的向通道发送,可以采取变通办法,即提前登记事件接收方,产生事件时逐个发送。例如:
package main import ( "context" "fmt" "sync" "time" ) type Transit struct { muListener sync.RWMutex listener []TransitEventInterface worker func(ctx context.Context, a ...any) (any, error) } func (t *Transit) NotifyStarted() { for _, l := range t.listener { if l == nil { continue } l.NotifyStarted() } } func (t *Transit) NotifyFinished() { for _, l := range t.listener { if l == nil { continue } l.NotifyFinished() } } type TransitEventInterface interface { NotifyStarted() NotifyFinished() } type TransitEventListener struct { TransitEventInterface } var notifiedStarted = make(chan struct{}) var notifiedFinished = make(chan struct{}) func (l *TransitEventListener) NotifyStarted() { notifiedStarted <- struct{}{} } func (l *TransitEventListener) NotifyFinished() { notifiedFinished <- struct{}{} } func (t *Transit) Run(ctx context.Context, a ...any) (any, error) { t.muListener.RLock() defer t.muListener.RUnlock() t.NotifyStarted() defer t.NotifyFinished() return t.worker(ctx, a...) } func worker(ctx context.Context, a ...any) (any, error) { if timer, ok := a[0].(int); ok && timer > 0 { time.Sleep(time.Duration(timer) * time.Second) } return a[0], nil } func NewTransit() *Transit { return &Transit{ worker: worker, listener: []TransitEventInterface{&TransitEventListener{}}, } } func main() { transit := NewTransit() finished := make(chan struct{}) startedTime := time.Now() finishedTime := time.Now() go func() { for { select { case <-notifiedStarted: startedTime = time.Now() case <-notifiedFinished: finishedTime = time.Now() finished <- struct{}{} return default: } } }() run, _ := transit.Run(context.Background(), 0) <-finished fmt.Println(time.Now(), "result:", run) fmt.Println(finishedTime.Sub(startedTime)) }
由于 fmt.Println()
方法在向屏幕输出内容时采取非阻塞形式,因此,直接在接收信号处直接输出会发现输出“started.”和“finished.”的顺序不固定。
为了保证尽可能精确测量开始和结束的时间差,建议采用上述记录时间点并在结束后计算时间差的方式。
到此这篇关于详解Golang如何监听某个函数的开始执行和执行结束的文章就介绍到这了,更多相关Go监听函数内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!