Go の select ステートメントでの優先順位制御
Go では、select ステートメントによりゴルーチン間の非同期通信が可能になります。ただし、case ブロックの評価順序によっては、予期しない結果が生じる場合があります。この問題は、コンテキストがキャンセルされたときにルーチンをすぐに終了するなど、特定のケースの処理を優先しようとするときに発生します。
次のコードを考えてみましょう。
func sendRegularHeartbeats(ctx context.Context) { for { select { case <-ctx.Done(): return case <-time.After(1 * time.Second): sendHeartbeat() } } }
問題:
このコードの目的は、time.After() よりも ctx.Done() ケースの処理を優先することです。 場合。ただし、Go の非決定的な評価順序により、time.After() ケースが最初に評価される場合があり、コンテキストがキャンセルされた場合でもハートビートが送信されることがあります。
解決策:
受け入れられた回答で提案された解決策は、ctx.Done() のノンブロッキングチェックを備えたネストされた select ステートメントを追加することを提案しています。ただし、ハートビートが送信される可能性は依然として高いため、これで問題が完全に解決されたわけではありません。
より効果的なアプローチは、デフォルトのケースを ctx.Done() ケースに追加して、ctx.Done() ケースの処理を優先することです。外側の選択ステートメント:
func sendRegularHeartbeats(ctx context.Context) { ticker := time.NewTicker(time.Second) defer ticker.Stop() for { select { case <-ctx.Done(): return default: } select { case <-ctx.Done(): return case <-ticker.C: sendHeartbeat() } } }
これにより、ctx.Done() ケースが外側の選択ステートメントで最初に評価され、優先順位が高くなります。コンテキストがキャンセルされた場合、ルーチンはすぐに戻り、ハートビートは送信されません。 time.After() ケースが最初に到着した場合、外側の select ステートメントのデフォルトのケースにより無視されます。
以上がGo の「select」ステートメントでコンテキストのキャンセルを優先するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。