API構築の基礎を学んだ。QConは、開発者コミュニティにおける知識とイノベーションの普及を促進することで、ソフトウェア開発に力を与える。実務者主導のカンファレンスであるQConは、チーム内のイノベーションに影響を与える技術チームのリーダー、アーキテクト、エンジニアリングディレクター、プロジェクトマネージャー向けにデザインされている。Sheehy氏は、人工知能ハイプ時代における責任ある開発者としてのあり方について、洞察に富んだ開会基調講演をした。Grizzanti氏が、「スタッフ・プラス」への道と、それを「科学」というより「芸術」としてとらえ、芸術を創作することとソフトウェアを創作すること、そして組織のダイナミクスに対処することの類似性について語っている。Codeを採用する:確認するべき6つの適性LCNC(ローコード/ノーコード)プラットフォームは、プログラマーだけでなくプログラマーでなくても、最小限のコーディングとワンクリックのデプロイメントで、アプリケーションソフトウェアを開発できるよう設計されている。ドラッグ&ドロップ方式のインターフェースなどを利用することで、開発・デプロイメントプロセスを簡素化し、効率的なアプリケーション開発とデプロイメントを実現する。6仮想マシンが提供するロック管理と同期の最適化に多くの注意を払ってきました。バイアスドロック、ロックの粗粒度化、エスケープ解析によるロックの削除、適応型スピンロックといった機能は、すべてアプリケーションのスレッド間でより効果的なオブジェクト共有を可能にし、並列性をより高めるために設計されたものです。した個々の機能は洗練されており、興味深いものですが、疑問があります;本当にこうした約束を果たしてくれているのでしょうか?2つのパートからなるこの記事では、私はこうした機能を詳しく調査します。シングルスレッドベンチマークの助けを借りて、パフォーマンスに関する疑問に答える試みをしようと思います。サポートされているロックの(ほとんどのスレッドライブラリと同様の)モデルは、非常に悲観的なものです。お互いに干渉しあう二つ以上のスレッドが同じデータを利用するような危険性がある時、これが問題を起こすことを避けるために、ロックを用いた厳格なソリューションを用いなくてはなりません。研究によると、ロックの競合が起きることはほとんど稀だということを示しています。言い換えると、スレッドがロックを取得しようとするときに、待ち状態にさせられることはほとんどないということです。ロックの獲得は、複数の順序づけられたアクションを引き起こします。その結果としてオーバーヘッドがはっきりと蓄積しますし、それを避けることもできません。私たちにはいくつかの選択肢があります。スレッドセーフなStringBufferを使うことを例にあげて考えてみて下さい。あなた自身に質問してみて下さい。StringBuilderを代わりに使わないのですか?関連スポンサーコンテンツほとんどのロックが競合せず、まれに競合する事があると言う事を知っていても、あまり役には立ちません。二つのスレッドが同じデータにアクセスする可能性がわずかにでも存在するならば、同期によるロックを使用してアクセス保護を行う事はほぼ必須だからです。結局、「本当にロックが必要だったのか?」と言う疑問に答える事が出来るのは、実行環境のコンテキスト内でロックを見つけたときだけです。HotSpotとJITにおいて実験を行ってきました。この作業により、私たちは今や適応スピンロックやバイアスド・ロック、そしてロックの疎粒度化とロック除去と言う二つの形式のロック省略を利用できます。ベンチマークを始める前に、こうした機能について調べるする時間を少し取り、それらがどのように動作するのかを全て理解しましょう。ロック除去に関する説明エスケープ解析とは、実行中のアプリケーション内で全参照のスコープを調べ上げると言うものです。この解析はHotSpotプロファイラの通常作業の一部として行われます。オブジェクトへの参照がローカルスコープに限定されていて、より広いスコープに"抜け出す(escape)"事がないと(エスケープ解析を通じて)HotSpotが理解できたなら、JITにたくさんの実行時最適化を適用する事が出来ます。した最適化の一つが、ロックの除去として知られているものです。ロックへの参照がいくらかのローカルスコープに限定されている場合、それが示唆するところは、ロックにアクセスするのはそのロックを作成したスレッドのみである、と言う事です。した条件の元では、同期ブロック内の値は絶対に競合する事がない、と言う事を表しています。これはつまり、私たちはそのロックを本当に必要としている訳ではないと言う事であり、安全に除去する事が出来ます。以下のメソッドを考えてみてください。ローカルのStringBufferを用いてStringの連結を行うもし私たちが変数sbをよく調べれば、concatBufferメソッドの境界内でのみ生存すると言う事をすぐに見つけられます。sbに対する参照は、それが宣言されたスコープから"抜け出す"事は絶対にありません。従って、他のスレッドがsbへのアクセスを行う方法は存在しないのです。これを踏まえると、私たちはsbに対するロック保護を除去できると言う事がわかります。一見するとロックの除去により、ロックが本当に必要とされない場所においては、あらゆる同期のペナルティ無しにスレッドセーフなコードを書く事が出来るように見えます。「それが本当に働いているのかどうか」と言う疑問については、ベンチマークで詳しく調べることにしましょう。バイアスド・ロックの説明バイアスド・ロックは、生存中に一つ以上のスレッドにアクセスされるロックはほとんどない、と言う観察結果に基づくものです。複数のスレッドがデータを共有する際、アクセスが競合する事はまれです。した観点からバイアスド・ロックの利点を理解するには、ロック(モニタ)がどのように獲得されるかを最初に調べる必要があります。ロックの獲得は、2つのステップからなるダンスです。あなたは、ロックの貸し出しを受ける必要があります。一度あなたが貸し出しを受けると、あなたはロックを手に入れるのは自由です。その貸し出しを受けるため、スレッドは高価なアトミック命令を実行する必要があります。ロックの解放とは、伝統的には貸し出しを放棄する事です。この観点からすると、コードの同期ブロックをスレッドがループ処理するような場合に、アクセスを最適化する事が出来るはずだと考えるのではないでしょうか。一つの例としては、ループ全体を含むようにロックの範囲を広げるなどです。すれば、スレッドはループの回数分ロックにアクセスする必要がなく、一度のアクセスで済むようになります。これは良い解決策ではありません。(そのロックの期間中ずっと)他のスレッドを閉め出す事になり、他のスレッドに対しても公平にアクセスを与える事が出来なくなるからです。理にかなったソリューションは、ループ中のスレッドに対してロックの優先的な利用を実現する(偏らせる=バイアス)ことです。スレッドに対するロックを偏らせるという事はつまり、スレッドがロックに対する貸し出しを解放する必要がなくなると言う事です。従って、その後のロック獲得はそれほど高価なものではなくなります。スレッドがロック貸し出しを解放するのは、他のスレッドがロックを獲得しようと試みたときだけです。6のHotSpot/JIT実装は、バイアスド・ロックの最適化をデフォルトで行います。ロックの疎粒度化についての説明さらにもう一つのスレッド最適化はロックの疎粒度化、もしくはマージです。ロックの疎粒度化は、隣接した同期ブロックを一つの同期ブロックにマージできそうだ、と言うときに起こります。このテーマに関するバリエーションとしては、複数の同期ブロックを一つに結合すると言うものです。この最適化は、同じロックオブジェクトが全てのメソッドによって使われている場合に適用されます。図2に示すような例を考えてみてください。ローカルでないStringBufferを用いてStringの連結を行うこの場合、StringBufferは非ローカルなスコープを持ち、いくつかのスレッドからアクセスされ得ます。従ってエスケープ解析は、このロックを安全に省略する事は出来ないと決定します。このロックが一つのスレッドからのみアクセスされるとしたら、バイアスド・ロックが適用されます。興味深い事に、ロック疎粒度化の決定は、そのロックの競合状態にあるスレッドの数とは無関係に行われます。3回のappendメソッドと、一度のtoStringメソッドです。最初に行われるアクションは、メソッドのインライン化です。私たちは、ロックを獲得する4回の呼び出しを、メソッド本体全てを囲む一つの呼び出しへと置き換える事が出来ます。最終的には、長い一つのクリティカルセクションが出来上がると言うことになるわけです。その結果(そのクリティカルセクション中はずっと)他のスレッドが停止させられるため、スループットが減ってしまいます。そのためループ内のロックは、ループの構築子を含むようには疎粒度化されません。スピンあるスレッドが、他のスレッドによるロックの解放を待っているとき、通常はオペレーティングシステムによって一時停止されます。スレッドを一時停止すると言う事は、CPU割当時間を消費しきる前にCPU外にスワップするよう、オペレーティングシステムに対して要求すると言う事です。ロックを保持するスレッドがクリティカルセクションを抜けたときに、一時停止されたスレッドを起こしてもらおうと言う訳です。そのスレッドは再スケジューリングされ、コンテキストスイッチによってCPUに復帰する必要があります。した一連の流れは全て、JVM、OS、ハードウェアに対して余分な負荷を強いる事になります。この問題解決に役立つであろう観察結果があります;ロックは通常非常に短い時間しか保持されないと言う事です。これは、ロックを獲得するためのウェイト時間が非常に短いのなら、スレッドを一時停止する必要はないだろう、と言う事を表しています。ウェイトするためには、スレッドをビジーなループ(スピン)させておけば良いと言う事です。このテクニックは、スピンロックとして知られています。スピンロックは、ロック期間が非常に短い場合にうまく働きます。そのロックが長時間保持される場合は、スピンしているスレッドが何もせずにCPUを消費するので、スピンは無駄となります。1.4.2でスピンロックが導入された際には、二つのフェーズに分割されていました。スレッドが一時停止される前に10回(デフォルト値)スピンしてみる、と言うものだったのです。1.6では適応型スピンが導入されました。適応型スピンでは、スピンする期間は全く決まっていません。同一のロック/ロック所有者の状態に対して、前回試行したスピンの結果に基づくポリシーによって決定されます。あるロックオブジェクトに対するスピンが最近成功したと言う履歴があり、実行中のスレッドが同じロックを保持しているなら、スピンは再度成功する可能性が高いと言う訳です。スピンがなかなか成功しないようなら、CPUサイクルを一切無駄にすることのないよう、そのままにしておかれます。StringBuffer対StringBuilderのベンチマークこうした全ての気の利いた最適化の効果をいかにして測定すればよいでしょう?それを正確に決定するのは単純なことではありません。何よりもまず、どんなベンチマークがよいのかと言うのが問題です。この質問に答えるために私が決めたのは、人々がいつもコード内で使用する一般的なイディオムをいくつか見ていこう、と言う事です。その中でもひときわ目立ったのは、「Stringの代わりにStringBufferを使用すると、どれほどコストの節約になるのか?」と言う古い質問でした。変更が必要なら、Stringの代わりにStringBufferを使おう、と言うものです。その理由はきわめてはっきりしています。Stringは変更不可であり、変更を必要としているなら、StringBufferの方がよりコストが低いと言うものです。ついて認識できていないのはとても興味深いことです。StringBuilderとStringBufferの間の違いは、単に同期の有無だけです。この二つをベンチマークで測定し、パフォーマンスに違いが生じるなら、それは同期のコストが表面化しているのだ、と考えられます。さあ、探検の始まりです。「競合しないロックのコストはどれほどなのだろうか」と言うのが最初の質問です。(リスト1に示した)ベンチマークの本質は、2?3個の文字列を連結すると言うものです。バッファの初期容量は、結合される三つの文字列を保持するのに十分な大きさです。これにより、クリティカルセクション内で行う作業量を最小化する事ができ、同期のコストに対する計測値がゆがめられないようにする事が出来ます。以下に示すのが、EliminateLocks(ロック省略)、UseBiasedLocking(バイアスド・ロックの使用)、DoEscapeAnalysis(エスケープ解析)の三つの選択肢の意味のある組み合わせの結果です。非同期のStringBuilderを使用する目的は、パフォーマンスの基準となる点を提供するためでした。最適化がStringBuilderのパフォーマンスに何らかの影響を与えるかどうかも気になった点です。結果からわかる通り、StringBuilderのパフォーマンスはベンチマークを通じて一定でした。これらのフラグはロックの使用を最適化する事を直接狙ったものだったため、この結果は期待通りです。パフォーマンス的には対極なものとして、あらゆる最適化無しに同期されたStringBufferを使用すると、だいたい3倍遅くなると言うのが見て取れます。図3に表されている結果を左から右に見ていくと、ロック省略がきちんとパフォーマンスを向上させているのがわかります。そのパフォーマンス向上は、バイアスド・ロックによってもたらされているものと比べると見劣りします。実際には、列Cを除けば、バイアスド・ロック付きの全ての実行結果は大体同程度のパフォーマンス向上をもたらしています。列Cは何でしょう?生のベンチマーク結果を扱っている過程で、6回に1回くらい明らかに長い時間がかかるということが注意を引きました。その違いは十分に大きく、ベンチマークが二つの完全に異なる最適化を報告しているように見えました。考えた結果、私は高い値と低い値を分けて報告する事に決めました(BとCです)。深く調査していない段階で、私に出来る事は仮説を立てる事だけです。その仮説とは、適用可能な最適化が一つ以上(二つが最有力)存在しており、ほとんどの場合バイアスド・ロックが勝利するが、常にそうなる訳ではない、と言うような競合条件が存在しているのではないか、と言うものです。他の最適化が勝つ事により、バイアスド・ロックは阻止されるか、適用が遅れるのです。エスケープ解析の結果も気になります。StringBufferのパフォーマンスがStringBuilderと同等になる事を期待していました。それが起こらなかった事は非常にはっきりしています。実行するごとに、私のマシン上での実行時間が変化したことです。何人かの同僚が、彼らのシステム上でテストしてみると、さらに良くわからないことが起きました。いくつかのケースでは、最適化によるスピードの向上があまり起こらなかったのです。3に示された結果は、私が期待したほどのものではありませんでしたが、ロックのオーバーヘッドのほとんどが最適化によって除去されると言う事を示しています。私の同僚たちによって行われたテストでは結果が異なり、結果の正確性が怪しまれる結果となってしまいました。このベンチマークは、ロックのオーバーヘッドを測定したものと言えるのでしょうか?まとめるにはまだ時期尚早で、まだ何か必要とされているのでしょうか?この記事のパート2(参考記事)では、このベンチマークをより深く見ていき、これらの疑問に答えたいと思います。その過程で気づいた事は、「結果を得る」と言うのは容易であると言う事、そしてその結果は私たちの疑問に対する答えを持っているのかも知れませんが、それを見つけ出すのがより困難なタスクだと言う事です。1.6.0_04を用いて実行しました。全ての最適化がサーバーVMに実装されている事に注意してください。それは、私のプラットフォームではデフォルトのVMではありません。JREでは利用できず、JDKでしか利用できません。サーバーVMを使うため、私は-serverオプションをコマンドライン上で指定しました。デフォルトではオンになっていますベンチマークを実行するため、ソースをコンパイルしてから以下のようなコマンドラインを使用してください。Borgersは、ITアーキテクト集団Xebiaのシニアコンサルタントです。Xebiaは、エンタープライズJavaとアジャイル開発に特化した、国際的なITコンサルタント会社兼プロジェクト組織です。エンタープライズJavaのパフォーマンス問題で顧客を助け、Javaパフォーマンスチューニングコースの講師を務めています。彼は1996年から開発者として、アーキテクトとして、チームリーダーとして、品質責任者として、助言者として、監査役として、パフォーマンステスターとチューニング担当者として、いくつもの業種で様々なJavaプロジェクトに従事してきました。彼は2005年から、もっぱらパフォーマンスの仕事に従事しています。謝辞この記事は、いろんな他の人の助けを得て完成する事が出来ました。分析の手伝いと、貴重な情報源を教えてくれました。貢献を行ったり、広範囲の編集作業を行ってくれたことに加え、その過程においても手助けしてくれました。SunのJVMバフォーマンスチームリーダーです。説明を行ってくれただけではなく、私を正しい方向に導いてくれました。Xebiaの同僚たちは、ベンチマークの実行を手伝ってくれました。Goetzなどの記事があります。毎週火曜日に前週のまとめコンテンツをお送りいたします。(日本語版は不定期リリース)25万人のシニアな開発者コミュニティーにぜひご参加ください。サンプルを見るあなたのメールアドレスはこちら国を選んでください。プライバシーポリシーに従って私の個人情報を扱うことに同意します。毎週火曜日に前週のまとめコンテンツをお送りいたします。(日本語版は不定期リリース)25万人のシニアな開発者コミュニティーにぜひご参加ください。サンプルを見る様々なイノベーターとアーリーアダプターがお送りするテクノロジーの概要を見る。自分がまだ知らないことに気づいていないと知るあなたが興味のあるトピックスをいつでも最新な情報に。あなたのメールアドレスはこちら国を選んでください。プライバシーポリシーに従って私の個人情報を扱うことに同意します。Inc.プライバシーBT。