I18n に見る複数のオプションをスレッドセーフにする方法

こんにちは、鈴木です。

 

Rails でリクエストごとにロケールを変更するには、リクエストごとに (before_action などで) I18n.locale に :ja や :en などを代入します。

 

I18n ってスレッドセーフ?

先日、「Rails4 のロケールってスレッドセーフだよね?」「デフォルトでスレッドセーフになったから大丈夫なはずだよね?」という話がありました。

結論から言うと、I18n はスレッドセーフに作られています。

 

スレッドセーフにするには?

そもそも Ruby でスレッドセーフなコードを書くときにやるべきことを振り返っておきましょう。

スレッドセーフにするには、以下のいずれかの方法をとります。

  • 複数スレッドで共有するリソースに対して Mutex  で保護する。
  • スレッドローカル変数を用いて、スレッド間でリソースを共有しないようにする。

 

I18n のスレッドセーフな実装

気になったので I18n のソースコードを読んでみると、このようになっていました。

Confin というクラスが I18n のオプションを保持する役割をしており、それがスレッドごとに保持されるようになっています。

そして、I18n.locale などのクラスメソッドは次のように実装されていました。

メタプログラミングに馴染みのない方には分かりづらいかもしれませんが、%w(locale backend ... load_path) のそれぞれについて、config から値の取得/設定を行うアクセッサを定義しています。

Config のインスタンスをスレッドごとに保持するようにしつつ、メタプログラミングでアクセッサをまとめて定義する、という手法です。

Ruby ではこのような実装を簡単に実現できて良いですね(^^

 

Comments are closed, but you can leave a trackback: Trackback URL.