为了账号安全,请及时绑定邮箱和手机立即绑定

包的 `init()` 函数中的无限 for 循环——好还是坏主意?

包的 `init()` 函数中的无限 for 循环——好还是坏主意?

Go
皈依舞 2023-07-31 15:56:39
我想知道在包的函数中使用无限 for 循环是否是一个坏主意,或者是否应该避免这样做。init()如果可以这样做或应该避免这种情况,是否有人有任何知识或经验?你会在哪里使用这个?例如,这可以用于提供来自外部源的一些信息的包,这些信息必须定期刷新(例如每天一次)。我使用了如下类似的代码,但没有“看门狗”功能。这意味着init()刚刚启动了一个 go 例程,该例程将在后台运行,并在蜱到达时运行更新过程。不幸的是,这个更新机制在 aprox 之后停止工作。由于未知原因,3 个月了,但服务运行良好,只是使用“旧”数据。简单示例实现完整示例请参见https://play.golang.org/p/k-GI1t9J4oPpackage infoimport (  "log"  "sync"  "time")var (  data map[string]interface{}  lock sync.RWMutex)func init() {  // ticker channel  ticker := time.NewTicker(1 * time.Second).C  // "watchdog" loop  for {    log.Println("Starting Update Loop")    var wg sync.WaitGroup    wg.Add(1)    // Start asyc update process.    go func() {      defer wg.Done() //notify wg when if process ends for whatever reason      // Loop forever      // Run when a tick is received from the `ticker` channel      for {        select {        case <-ticker:          log.Println("Update ticker received")          err := update()          if err != nil {            log.Printf("ERROR: %v\n", err.Error())          }        }      }    }()    wg.Wait()  }}// internal update function that retrieves some information from some external systemfunc update() error {  lock.Lock()  defer lock.Unlock()  log.Println("Update `data`")  // retrieve information and update `data`  return nil}// Public function to query datafunc GetInformation(key string) interface{} {  lock.RLock()  defer lock.RUnlock()  return data[key]}该代码可以正常工作并在单元测试中运行良好,并且也可以正常运行。我想知道长期稳定性(一年或更长的正常运行时间)等等。
查看完整描述

1 回答

?
繁星点点滴滴

TA贡献1803条经验 获得超3个赞

它位于 goroutine 中,因此技术上没有问题,但直接在 an 中实现行为init会使其非常难以使用,原因有两个:

  1. 测试很难,就像main测试很难一样。测试是否调用另一个函数要容易得多init,然后可以对其进行测试。

  2. 很难推理。“自动”发生的事情越多,对于使用该包的任何开发人员(包括未来的你)来说,它的意义就越小。“好吧,我导入了这个包并使用了一个微小的函数,现在不知怎的,我的 CPU 使用率从 1% 上升到了 50%,我做错了什么”,这样的事情将会出现,需要更多的探索才能弄清楚。

TL;DR 不存在“长期稳定性”问题,但很可能存在长期可维护性问题。


查看完整回答
反对 回复 2023-07-31
  • 1 回答
  • 0 关注
  • 53 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信