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

我想知道在包的函数中使用无限 for 循环是否是一个坏主意,或者是否应该避免这样做。init()

如果可以这样做或应该避免这种情况,是否有人有任何知识或经验?

你会在哪里使用这个?

例如,这可以用于提供来自外部源的一些信息的包,这些信息必须定期刷新(例如每天一次)。

我使用了如下类似的代码,但没有“看门狗”功能。这意味着init()刚刚启动了一个 go 例程,该例程将在后台运行,并在蜱到达时运行更新过程。

不幸的是,这个更新机制在 aprox 之后停止工作。由于未知原因,3 个月了,但服务运行良好,只是使用“旧”数据。

简单示例实现

完整示例请参见https://play.golang.org/p/k-GI1t9J4oP

package info


import (

  "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 system

func update() error {

  lock.Lock()

  defer lock.Unlock()

  log.Println("Update `data`")

  // retrieve information and update `data`

  return nil

}


// Public function to query data

func GetInformation(key string) interface{} {

  lock.RLock()

  defer lock.RUnlock()

  return data[key]

}

该代码可以正常工作并在单元测试中运行良好,并且也可以正常运行。我想知道长期稳定性(一年或更长的正常运行时间)等等。


皈依舞
浏览 77回答 1
1回答

繁星点点滴滴

它位于 goroutine 中,因此技术上没有问题,但直接在 an 中实现行为init会使其非常难以使用,原因有两个:测试很难,就像main测试很难一样。测试是否调用另一个函数要容易得多init,然后可以对其进行测试。很难推理。“自动”发生的事情越多,对于使用该包的任何开发人员(包括未来的你)来说,它的意义就越小。“好吧,我导入了这个包并使用了一个微小的函数,现在不知怎的,我的 CPU 使用率从 1% 上升到了 50%,我做错了什么”,这样的事情将会出现,需要更多的探索才能弄清楚。TL;DR 不存在“长期稳定性”问题,但很可能存在长期可维护性问题。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go