第1回 マルチスレッドはこんなときに使う:連載.NETマルチスレッド・プログラミング入門(2/2 ページ)
難解なマルチスレッド・プログラミングを基礎から解説。まずはその動作原理を理解し、活用すべき場面を見極める。
マルチスレッド・プログラミングの目的はパフォーマンス向上
マルチスレッド処理の目的を、ツリー状に図解してみた。マルチスレッドの目的であるパフォーマンスの向上を詳しく分類すると、レスポンス・タイムとスループットの向上の2つに分類することができる。
以下では、レスポンス・タイム向上とスループット向上について、それぞれ詳しく見ていく。
■レスポンス・タイムの向上
マルチスレッド・プログラミングでパフォーマンスを向上できる効果の高いパターンが、レスポンス・タイムの向上である。レスポンス・タイムとは、処理のリクエストを出してから、最初の反応が返ってくるまでの時間である。例えば、マウスをクリックしてから、その反応を画面上で認識できるまでの時間ということになる。この場合、レスポンス・タイムの向上はユーザー・インターフェイスの使い勝手の向上に直結する。
マルチスレッドで実現できるレスポンス・タイムの向上は、重い処理を実行しているときでも、ほかの処理に対して即時に反応できるようにするということである。ここで重い処理とは、時間のかかる計算や、ネットワークによる通信、ディスクへのアクセスなどである。即時に反応するべき処理とは、ユーザー・インターフェイスからの入力や、サーバであればほかのクライアントからの要求などである。このような場面でマルチスレッドを用いないとすると、重い処理を実行している間、ユーザー・インターフェイスやクライアント・アプリケーションはフリーズしてしまうことになる。
それぞれ具体例を挙げてみよう。例えば、ブラウザはHTMLデータをWebサーバからネットワークを通してダウンロードし、解析表示するプログラムである。当然、ネットワーク越しにデータをダウンロードするには時間がかかる。ほとんどのブラウザでは、実は、このネットワーク越しにデータをダウンロードするという部分は別スレッドで動作している。そのため、HTMLデータのダウンロードが完了し、目的のWebが完全に表示される前でも、[戻る]ボタンや[中止]ボタンはクリック可能であり、ブラウザはユーザーの操作に即座に反応する。もし、シングルスレッドでプログラミングされたブラウザであれば、Webサーバにアクセスを開始したときから、データが完全にダウンロードされるまで、ユーザーからのマウスの入力をまったく受け付けなくなってしまうだろう。
プログレスバーを使用するときも、マルチスレッド化が必要となる。プログレスバーは、ある重い処理の進行状況を示すものであるが、重い処理が終了するまで、そのステータスを更新しないのでは意味がない。プログラムが何か重い処理をしている間でも、逐次プログレスバーの表示状態を更新するためには、重い処理とプログレスバーの更新処理を別々のスレッドで動作させる必要がある。
サーバ上でのプログラムの例も考えてみよう。Webサーバなどのサーバ・プログラムは、複数のクライアントからのアクセスを同時に受け付けることができるようにプログラムされている。ここでもマルチスレッドが役に立つ。
サーバ・プログラムがシングルスレッドの場合には、一度に1つのクライアントからの処理しか受け付けられないことになってしまう。もし、あるクライアントが時間のかかる処理をリクエストしたならば、その処理が終わるまでは、ほかのクライアントは待たされることになるだろう。これをマルチスレッドにすることによって、各クライアントへの処理時間を平準化することができるようになり、複数クライアントのリクエストをバランス良く処理できるようになる。
■スループットの向上
マルチスレッドによって、遅いデバイスに対するCPU待機時間の利用や、マルチプロセッサ環境を効率よく利用でき、システム全体のスループットも向上させることができる。
前者のパターンでは、CPUが遅いデバイスの処理結果を待っているときに生じる無駄な時間をマルチスレッド化によって活用する。遅いデバイスとはディスクやネットワークなどである。これらはメモリなどに比べるとアクセスに時間がかかる。
例えば、ディスク上にあるすべてのファイルをリストアップするような処理を行うとき、ディスクにアクセスしている時間は非常に長くなるが、その間CPUでの処理はほとんどない。このようなCPUの空き時間がパフォーマンス向上の余地になる。ディスクへのアクセス処理を別スレッドで実行することにより、メインのスレッドではCPUを利用したほかの処理を行うことができるようになり、全体のスループットは向上する。
ネットワークへのアクセスも、ディスクほどではないが時間がかかる。先ほど、ダウンロードのためのスレッドと、ユーザー・インターフェイスのためのスレッドを持つブラウザの例を挙げたが、たいていのブラウザでは、ダウンロード用のスレッドは1つではなく複数個となっている(そしてまた、たいていのWebサーバはマルチスレッドにより複数アクセスを同時に処理できる)。これにより、HTMLファイルのダウンロードと、そのページに含まれているいくつかの画像ファイルのダウンロードが同時に処理でき、ページ全体が表示されるまでの時間を短くしている。
もう1つのパターンがマルチプロセッサの効率的利用である。前述したように、ハードウェアの進化により1台のコンピュータに複数のCPUを搭載するマルチプロセッサが登場してきた。マルチスレッドを用いて明示的に複数の処理を走らせることによって、マルチプロセッサの並行処理の恩恵を受け、その処理性能を十分に発揮できるようになる。
マルチスレッド化で速度向上が期待できる場面は限られている
マルチスレッド化によってアプリケーションを高速化できるとよくいわれているが、解説してきたように、実は高速化できる場面もその効果も限られていることが分かっていただけただろう。
レスポンス・タイムの向上は、最も効果が大きいマルチスレッドによる高速化である。ユーザー・インターフェイスがフリーズする場面や、サーバ的な動作により複数のクライアントからのリクエストに応えなくてはならない場合には、ほぼ慣用的に用いられる。注意しなくてはならないのは、レスポンス・タイムの向上の場合、高速化というのは、あくまでユーザーから見た反応についてであり、実際に処理をすべて完了するまでの時間、つまりスループットは良くならないということである。マルチスレッド化のオーバーヘッドにより、スループットはむしろ悪化する。
スループットの向上が期待できる場面は、さらに限定的である。マルチプロセッサ環境であれば確かにその向上が期待できるが、Windowsでは、よほど高級なサーバ・マシン以外ではシングルCPUであることが普通で、利用できる環境は限られてくる。遅いデバイスに対するI/Oの待ち時間の利用も、使用できる場面は限られてくるであろう。
このように、どのような場面でもマルチスレッド化すればパフォーマンスが向上するわけではないということに注意しなくてはならない。それと同時にマルチスレッド化は、冒頭で述べたとおり、デッドロックやデータの破壊などが発生する可能性のある、非常にリスクを伴うプログラミング技法である。
もちろん、パフォーマンスの向上が望める場面ではマルチスレッド化をするべきであるし、使うべき場面でマルチスレッドを使用しないと使い勝手の悪いプログラムとなってしまう。必要となる場面を的確に判断し、慎重にプログラミングを行い、少ないリスクで最大限の効果を上げるようなプログラムを設計しなくてはならない。
以上、今回はスレッドが動作する仕組みについて説明し、マルチスレッドの目的を分類することにより、マルチスレッド・プログラムが有効となる場合の処理について見てきた。次回からは、.NETでマルチスレッド・プログラムを作成するための具体的なプログラミングについて解説していく。
Copyright© Digital Advantage Corp. All Rights Reserved.