php小编西瓜认为,"由 time.AfterFunc() 递归调用的 goroutine 的设计很糟糕"这句话反映了一种不合理的设计思路。在并发编程中,递归调用的 goroutine 可能导致资源消耗过大,甚至引发死锁和内存溢出等问题。因此,应该谨慎使用递归调用,并考虑使用其他替代方案来解决问题,以确保程序的性能和稳定性。在编写代码时,我们应该时刻关注设计的合理性,避免出现不必要的问题。
问题内容
我有一个小型 http 应用程序 (A)。在启动时,它调用另一个 http 服务 (B) 来验证许可证,如果许可证正常,则 http 服务器 (A) 启动。如果验证失败A则出现致命错误退出
许可证检查每 24 小时进行一次
每 24 小时递归创建一个新的 goroutine 会被认为是一个糟糕的设计吗?检查下面我的代码。之前的goroutine会关闭还是继续运行然后n个goroutine互相调用而结束
每个新的 goroutine 是从主 goroutine 调用还是从子 goroutine 调用?
func Request(retry bool) error {
// request and verify license (external http service)
err := verify_license()
if err != nil {
return err
}
if retry {
// Renew verification timeout (renew license every 24 hours)
time.AfterFunc(LICENSE_TIMEOUT, func(){
request_retry()
})
}
return nil
}
func request_retry(){
for i := 0; i < LICENSE_RETRY; i++ {
if err := v.Request(false); err == nil {
break
}
time.Sleep(LICENSE_RETRY_TIMEOUT)
}
time.Sleep(LICENSE_TIMEOUT)
v.Request(true)
}
if err := license_verify.Request(true); err != nil {
log.Fatal(err.Error())
}
解决方法
也许你可以重新思考问题的设计。例如:
func main() {
if !checkLicense() {
log.Fatal("license check failed")
}
srv := http.Server{} //
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
go func() {
for {
select {
case <-ctx.Done(): // in case you want to instal signal handlers etc
return
case <-time.After(24 * time.Hour):
if !checkLicense() {
cancel() // or srv.Shtdown, really depends on you
}
}
}
}()
if err := srv.ListenAndServe(); err != nil {
log.Fatal(err)
}
}
func checkLicense() bool {
// add retries per request here
}
基本上,它的作用是创建一个 goroutine,定期检查并在出现问题时通知上下文或通道。
如果我正确理解了这个问题,那么你只需要保持简单即可。一个构建块是请求失败时重试。除此之外,是 24 小时重试。最后一层是,如果检查失败,则对其做出反应。您可以使用上下文、频道或您真正喜欢的任何内容
以上就是由 time.AfterFunc() 递归调用的 goroutine 的设计很糟糕的详细内容,更多请关注编程网其它相关文章!