优先选择具有通道的案例

huangapple go评论90阅读模式
英文:

Priority on Select cases with channel

问题

我有这个函数,使得其中的方法在一个定时器上运行。我的问题是,第二个 case sigC 只有在 case ticker.C 完成后才起作用,这并不理想,因为程序是带有标志的运行的,所以如果我想改变标志并改变程序的行为,我必须等待定时器方法运行完成,而这可能需要一些时间。

我的目标是,当我按下 Ctrl+C 时,程序立即停止运行。

func report() error {
    ticker := time.NewTicker(timeConfig)

    sigC := make(chan os.Signal, 1)
    signal.Notify(sigC, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT, os.Interrupt)

    for range ticker.C {
        select {
        case <-ticker.C:
            connection = connectionInit()

            tagValues, err := fetchLatestTags()
            if err != nil {
                return err
            }
            if len(tagValues) >= threshold {
                metrics, err := fetchMetrics(tagValues)
                if err != nil {
                    return err
                }
                if stdout {
                    err = locally(metrics)
                    if err != nil {
                        return err
                    }
                } else {
                    err = sendMail(metrics)
                    if err != nil {
                        return err
                    }
                }
            }
            connection.Close()
        case <-sigC:
            return nil
        }
    }
    return nil
}

我尝试了这些解决方案,它们非常相似,但都没有成功:

[1]https://stackoverflow.com/questions/46200343/force-priority-of-go-select-statement

[2]https://stackoverflow.com/questions/11117382/priority-in-go-select-statement-workaround

英文:

I have this function so that the methods inside, run on a ticker. My problem is that the second case, sigC, only works after the case ticker.C is complete, which is not ideal because the program runs with flags, so if I want to change the flags and alter the program's behaviour, I have to wait for the ticker methods to finish running, and that can take some time.

My objective is that when I press Ctrl+C, the program finishes running immediately.

func report() error {
	ticker := time.NewTicker(timeConfig)

	sigC := make(chan os.Signal, 1)
	signal.Notify(sigC, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT, os.Interrupt)

	for range ticker.C {
		select {
		case &lt;-ticker.C:
			connection = connectionInit()

			tagValues, err := fetchLatestTags()
			if err != nil {
				return err
			}
			if len(tagValues) &gt;= threshold {
				metrics, err := fetchMetrics(tagValues)
				if err != nil {
					return err
				}
				if stdout {
					err = locally(metrics)
					if err != nil {
						return err
					}
				} else {
					err = sendMail(metrics)
					if err != nil {
						return err
					}
				}
			}
			connection.Close()
		case &lt;-sigC:
			return nil
		}
	}
	return nil
}

I tried these solutions which are pretty similar to each other but to no avail:

[1]https://stackoverflow.com/questions/46200343/force-priority-of-go-select-statement

[2]https://stackoverflow.com/questions/11117382/priority-in-go-select-statement-workaround

答案1

得分: 2

如果我理解正确,你想要将循环遍历通道的部分替换为一个无限循环。即 for range ticker.C { ... } -> for { ... }

如果你希望程序在不等待 case <-ticker.C: 块中的代码执行完毕时立即结束,你应该在一个单独的 goroutine 中执行该代码块,并将 case <-sigC: 块中的 return nil 更新为 os.Exit(1)

func report() {
	ticker := time.NewTicker(timeConfig)
	defer ticker.Stop()

	sigC := make(chan os.Signal, 1)
	signal.Notify(sigC, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT, os.Interrupt)

	for {
		select {
		case <-ticker.C:
			go func() {
				connection = connectionInit()

				tagValues, err := fetchLatestTags()
				if err != nil {
					return
				}
				if len(tagValues) >= threshold {
					metrics, err := fetchMetrics(tagValues)
					if err != nil {
						return
					}
					if stdout {
						err = locally(metrics)
						if err != nil {
							return
						}
					} else {
						err = sendMail(metrics)
						if err != nil {
							return
						}
					}
				}
				connection.Close()
			}()
		case <-sigC:
			os.Exit(1)
		}
	}
}
英文:

If I understood correctly what you want to do is to replace the range-over-channel loop with an infinite loop. i.e. for range ticker.C { ... } -> for { ... }.

And if you want the program, rather than the report function, to finish immediately without waiting on the code in the case &lt;-ticker.C: block to finish, you should execute that block of code in a separate goroutine and update the case &lt;-sigC: block from return nil to os.Exit(1).

func report() {
	ticker := time.NewTicker(timeConfig)
	defer ticker.Stop()

	sigC := make(chan os.Signal, 1)
	signal.Notify(sigC, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT, os.Interrupt)

	for {
		select {
		case &lt;-ticker.C:
			go func() {
				connection = connectionInit()

				tagValues, err := fetchLatestTags()
				if err != nil {
					return
				}
				if len(tagValues) &gt;= threshold {
					metrics, err := fetchMetrics(tagValues)
					if err != nil {
						return
					}
					if stdout {
						err = locally(metrics)
						if err != nil {
							return
						}
					} else {
						err = sendMail(metrics)
						if err != nil {
							return
						}
					}
				}
				connection.Close()
			}()
		case &lt;-sigC:
			os.Exit(1)
		}
	}
}

huangapple
  • 本文由 发表于 2022年3月17日 19:56:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/71511901.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定