どうもこんにちは。プログラマの田中智大です。
月に一度で社員とサバゲーに参加してます。私はスナイパーをやってるんですが、これがまた楽しいです。
今回はサバゲー… じゃなくてサーバーのお話を一つ。
サーバーでアクセスがあった時に自分が何番目のアクセスかを取得し、ちょうど100番目にアクセスしたユーザーには100万円を進呈するというような処理を実装する必要があったときに、試しに ASP.NET で作ったサーバーAPI でアクセス数を static変数でカウントするように実装してみました。
こんな感じのプログラムです。
static変数を見るとその時点でどれだけアクセスがあったかが分かり、ちょうど100回目のアクセスの人には100万円あげる事ができると思っていたのですが、実はこの設計では…
「 正常に動かない事がありえるのです! 」
どういうことかを説明していきたいと思います。
◆なぜ正常に動かないの?
今回正常に動いてくれない理由は
「 IIS は同時に複数の要求でプログラムを動かした時はマルチスレッドで実行される 」
というところにあります。マルチスレッドで動いている以上、時には複数のスレッドが同じタイミングで同じ処理を行う(同じ変数を使う)ことだってありえます。
今回作ったクラスの static変数「AccessCount」はスレッド間で共有されますので、別々のスレッドでも addAccessCount() を呼び出した時は同時に同じ値を使う事になるんです。
※ addAccessCount() は今回説明のため、あえて関数化しています。詳細については次回以降で説明します。
◆どんな動きになるの?
では、今回の実装でどういった事が起きてしまう可能性があるのかこちらのアニメーションで見てみましょう。
Aさん、Bさん、Cさん、Dさんはたとえ同じタイミングだったとしても100番目にアクセスした人は1人であってほしいのですが、addAccessCount() はその時点の AccessCount に1を足したものを返すため、4人とも「100番目にアクセスした人」になり、結果4人に100万円をあげるハメになっちゃいます。
さらに気をつけないといけないのが、要求が始まったタイミングは異なったとしても、内部の処理速度の違いからある時点で全く同じタイミングで同じ関数を呼び出す事は十分にあり得ます。
◆同時になんて滅多に無いんじゃ…?
先ほどのアニメーションではスレッドが4つ、つまり4つの要求を意図的に同じタイミングにしているため起きる事は無いように見えるかもしれませんが、もし10万以上のユーザーがいて、秒間1000以上のアクセスがあるようなサービスで今回のような処理が使われていたらどうでしょうか?
起こらないなんて言えるでしょうか…?
◆おわりに
IIS で static変数を扱うときは、複数の要求はマルチスレッドで動く事から同時に処理が実行されてしまう可能性がある事を理解しておく必要があります。
今回はアクセスカウンタで説明しましたが、皆さまも IIS のサーバー実装で staticな変数を使ってしまっているような事はないでしょうか?
もし使っている場合は、それが複数の要求で動いた時に意図した挙動になるかどうかを考えていただければと思います。
一緒に面白いゲームを作っていきましょう!
採用情報
月に一度で社員とサバゲーに参加してます。私はスナイパーをやってるんですが、これがまた楽しいです。
今回はサバゲー… じゃなくてサーバーのお話を一つ。
サーバーでアクセスがあった時に自分が何番目のアクセスかを取得し、ちょうど100番目にアクセスしたユーザーには100万円を進呈するというような処理を実装する必要があったときに、試しに ASP.NET で作ったサーバーAPI でアクセス数を static変数でカウントするように実装してみました。
こんな感じのプログラムです。
static変数を見るとその時点でどれだけアクセスがあったかが分かり、ちょうど100回目のアクセスの人には100万円あげる事ができると思っていたのですが、実はこの設計では…
「 正常に動かない事がありえるのです! 」
どういうことかを説明していきたいと思います。
◆なぜ正常に動かないの?
今回正常に動いてくれない理由は
「 IIS は同時に複数の要求でプログラムを動かした時はマルチスレッドで実行される 」
というところにあります。マルチスレッドで動いている以上、時には複数のスレッドが同じタイミングで同じ処理を行う(同じ変数を使う)ことだってありえます。
今回作ったクラスの static変数「AccessCount」はスレッド間で共有されますので、別々のスレッドでも addAccessCount() を呼び出した時は同時に同じ値を使う事になるんです。
※ addAccessCount() は今回説明のため、あえて関数化しています。詳細については次回以降で説明します。
◆どんな動きになるの?
では、今回の実装でどういった事が起きてしまう可能性があるのかこちらのアニメーションで見てみましょう。
![]() |
同時実行の挙動 |
Aさん、Bさん、Cさん、Dさんはたとえ同じタイミングだったとしても100番目にアクセスした人は1人であってほしいのですが、addAccessCount() はその時点の AccessCount に1を足したものを返すため、4人とも「100番目にアクセスした人」になり、結果4人に100万円をあげるハメになっちゃいます。
さらに気をつけないといけないのが、要求が始まったタイミングは異なったとしても、内部の処理速度の違いからある時点で全く同じタイミングで同じ関数を呼び出す事は十分にあり得ます。
◆同時になんて滅多に無いんじゃ…?
先ほどのアニメーションではスレッドが4つ、つまり4つの要求を意図的に同じタイミングにしているため起きる事は無いように見えるかもしれませんが、もし10万以上のユーザーがいて、秒間1000以上のアクセスがあるようなサービスで今回のような処理が使われていたらどうでしょうか?
起こらないなんて言えるでしょうか…?
◆おわりに
IIS で static変数を扱うときは、複数の要求はマルチスレッドで動く事から同時に処理が実行されてしまう可能性がある事を理解しておく必要があります。
今回はアクセスカウンタで説明しましたが、皆さまも IIS のサーバー実装で staticな変数を使ってしまっているような事はないでしょうか?
もし使っている場合は、それが複数の要求で動いた時に意図した挙動になるかどうかを考えていただければと思います。
採用情報
クラウドクリエイティブスタジオではエンジニアの方を絶賛募集中です。一緒に面白いゲームを作っていきましょう!
採用情報
コメント
コメントを投稿