Thread と ThreadPool どっちがスレンダー?

ThreadPool

Thread プログラミングってめんどくさいよね。すぐハングアップするし、わけのわからない動作とか理解させたくなさげな仕様とかね。いやだよね。でも アプリのUI処理がどんどん重くなって固まりがちになってから Thread を導入しようと思ってもうまくいかない。最初から、どこをどう Thread に分けておくかって設計しとかないと、だいたいバグだらけになって頓挫ですよ。そんなわけで、Thread は自分でもいろんなテストして経験値をあげておく必要があるよね。

今回は ThreadPool を使ってみましょ。なんたって、恥ずかしながらこれまで使ったことないですし。あーお恥ずかしい。それで、 「連載! とことん C#: 第 12 回 スレッド プールと Web アプリの問題」を読んでみたの。すると、ThreadPoolを使うといいよ、軽いよって書いてあるじゃない。そんなわけで、同じような処理をしたときに ThreadThreadPool でどのくらい時間が違うのかを体験しようってわけです。

 

ThreadとThreadPoolの時間を測るコード

もういきなりコードいきますよ。今回も、.NET 2.0、C#で書いてます。2つのテスト関数で。まずは、Thread。例によって Stopwatch で測ってます。ElapsedMilliseconds だけだと 0 msec になっちゃうので、ElapsedTicks も記録しました。

private void startThreadTest()
{
	swatch.Reset();
	swatch.Start();
	comm.done = false;
	Thread t = new Thread(testThread);
	t.Start(comm);
	while (!comm.done)
	{
		// おまち
	}
	swatch.Stop();
	while (t.ThreadState != System.Threading.ThreadState.Stopped)
	{
		// おまち
	}
	textBoxLog.Text += "Thread,"+swatch.ElapsedTicks + "," + swatch.ElapsedMilliseconds;
}

ThreadPool のほうも似たようなコード。

private void startThreadPoolTest()
{
	swatch.Reset();
	swatch.Start();
	comm.done = false;
	ThreadPool.QueueUserWorkItem(testThread, comm);
	while (!comm.done)
	{
		// おまち
	}
	swatch.Stop();
	textBoxLog.Text += "ThreadPool," + swatch.ElapsedTicks + "," + swatch.ElapsedMilliseconds;
}

あっと、comm ってのは Thread とデータをやり取りしたいときに使うクラスthreadCommのインスタンスです。こんな感じで定義してあります。

public class threadComm : Object
{
	public bool done;
}

中身は何もないです。インスタンスを作るときは、volatile をつけます。これつけないと、 while (!comm.done) {// おまち } ってループが本物の無限ループになります。こういうのが Thread では大事。

volatile threadComm comm = new threadComm();

それから、肝心のスレッドはこれ。ただ done=true を代入しているだけで終了します。

static void testThread(Object o)
{
	threadComm com= o as threadComm;
	com.done= true;
}

threadpool

肝心なところは紹介しました。あとは2つのテスト関数をぐるぐるまわして1000回くらい実行して時間を測ります。時間を測ったら、Excel にコピペしてヒストグラムを見てみましょう。なお、このマシンではおおむね 2814ticks/msec=2.8ticks/μsec と調べてあるので、ticks を μsec に換算してグラフを書いてみました。また、1000回のうち100回分の時間の長いデータはおそらく他のプライオリティの高い処理が割り込んでいたと考えてデータから除外しました。

ThreadPoolはThreadの10倍以上速いのだ

まず、Thread です。平均値は 374μsec あたりです。ふた山になっているのは、何か条件の良い時の分布とやや悪条件の時の分布のふたつがあるのでしょう。いずれにしても、引き数1つの Thread を起動して、終わるまでに 400μsec くらいはかかっています。長いですね。条件が悪い時はさらに長いらしいということです。

thread-histgram

で、ThreadPool のほうも見ると、平均値は 27μsec あたりで Thread の 10倍以上速いことがわります。こちらは、OSがあらかじめ用意しておいてくれた Pool を利用するから早いんですね。細かくたくさんの Thread を動かす時なんかは、断然こっちのほうがいい。

threadpool-histgram

こんな大きな違いが出ると思ってなかったので、驚きでした。これまで、何も考えずにひな型プログラムを引っ張ってきて Thread 作って動かしてましたが、これからは反省して ThreadPool を活用していかねばです。みなさまもぜひに。

あ、もし何かまちがい見つけたら教えてください。お願いしますよ!

 

参考

  • 連載! とことん C#: 第 12 回 スレッド プールと Web アプリの問題(MSDN、デベロッパーセンター)
    http://code.msdn.microsoft.com/windowsdesktop/12-Web-5ea33584
  • ThreadPoolクラスによるマルチスレッド
    連載 .NETマルチスレッド・プログラミング入門 by 高木健一さん
    http://www.atmarkit.co.jp/fdotnet/mthread/mthread02/mthread02_03.html
  • ThreadPool クラス(MSDN)
    http://msdn.microsoft.com/ja-jp/library/system.threading.threadpool%28v=vs.80%29.aspx
印刷
You can skip to the end and leave a response. Pinging is currently not allowed.
Subscribe to RSS Feed Twitter は Ume108 だよ