https://news.ycombinator.com/item?id=8103128
1 comment | 0 points | by WazanovaNews 約3時間前 edited
The Go Blogにおける、
Goサーバにおいては、goroutineが受取ったリクエストに対応する。request handlerは、DBやRPCサービスなどバックエンドにアクセスするために、複数のgoroutineを起動させることがよくある。それらのgoroutineは、ユーザのアイデンティティ / 認証トークン / リクエストの期限など、そのリクエストのスコープ内の変数にアクセスする必要がある。また、リクエストがキャンセルになったり、タイムアウトすれば、一連のgoroutineは直ちにexitして、システム側がリソースを確保できるようにする必要がある。
Googleでは、リクエストのスコープ内の変数 / キャンセルのシグナル / リクエストの期限などの情報を、リクエストを処理しているgoroutineにAPIの境界をまたいで簡単に渡すことができるように、
contextパッケージを開発した。GoogleにおいてGoで開発するエンジニアは、やり取りするリクエストのコールパスにおける、全てのfunctionの最初の引数としてContextパラメータを渡すようにと決めている。
という話の、背景/ニュアンスを掴むのに役立ちそうなコメントがHNにありました。
このパターンは、Goとthread-stateなデータ構造を採用する言語との根本的な違いを表している。thread-stateの引数は、願わくば既にthread-stateに入っていてほしいと期待しいて、全てのfunctionにcontext変数のようなものが渡されることは必須としていない。この「願わくば」という考え方が、自分がthread-stateを気に入らない理由。並列処理をしたければ、一つのスレッドの状態を次に伝達しなくてはいけない。他のスレッドが存在することは保証されていないので、プログラマーは、そこにあってほしいと願うか、確認するか、いずれにしても煩わしい。
contextを渡す手法だと、そのような希望的観測はいらないが、各functionがcontextを渡していく必要がある。Goでの中規模開発案件に取組んでいたとき、スタックの底の方でcontextが必要になり、ツリーの上の方のfunctionに追加していくはめにしばしばなった。だから、全てのfunctionが常にcontextを保持することを標準のルールにするのはよい考えだと思う。心配が減るし、後からかなりコードを増やすという作業もなくなる。
また、「Goの標準httpインターフェース上で構築されたミドルウェアパッケージでは、Contextをどうすればよいのか?functionのパラメータとしてContextを宣言しなくてはいけないように見えるけど。自分は何か認識ちがっている?」という質問に対しては、Googleにおける二つのアプローチを紹介しています。
1) 必要なfunctionには明示的にContextパラメータを追加。最初のパラメータになることがよくあり、名称は ”ctx” としている。どうやってfunctionをキャンセルし、情報を渡すかをはっきりさせることができるが、手間はかかる。自動化のために、Contextのフローを追える静的な分析ツールと自動のリファクタリングツールを開発中。
2) http.RequestをContextにmapするパッケージを利用。http.RequestのmapにContextを登録し、リクエストが完了するとはずす、サーバハンドラーに必要になる。例えば、gorilla contextパッケージがある。
また、
タイプセーフではない。Contextを受取る各functionは、暗黙のインターフェース(呼び出す側がcontextに含めなくてはいけないkey/valueペア)を持ち、期待されるバインディングがなければ、ランタイムエラーになる可能性が高い。
という指摘に対しては、
(上記の)分析ツールとリファクタリングツール(によって、Contextが正しくスレッドされているかがもっと簡単に確認できるようになる。)は、すぐにはできないが、できあがれば皆が使えるようにする。ひとまず今回は、Contextについて皆に周知して、使ってもらい、そして、新しいコードやフレームワークに取り入れていく。
と回答しています。
contextパッケージの使い方と例は、The Go Blogに詳細掲載されています。
#golang