Delegate.BeginInvokeに重い処理はさせるな
Delegateを使って手軽に非同期処理を行うことが出来ますが、これには落とし穴があります。
using System; using System.Threading; delegate void Rush(); class Program { static void TheWorld() { Console.WriteLine("\nザ・ワールド!! 時よ止まれ!\n"); while (true) Thread.Sleep(Int16.MaxValue); } static void Muda() { Console.Write("無駄"); while (true) Thread.Sleep(Int16.MaxValue); } static void Mudaa() { Console.WriteLine("無駄ァ!!!!"); Thread.Sleep(1000); Console.WriteLine("\nそして時は動き出す\n"); Thread.Sleep(1000); } static void Time(object o, System.Timers.ElapsedEventArgs e) { Console.WriteLine(e.SignalTime); } static void Main(string[] args) { System.Timers.Timer t = new System.Timers.Timer(); t.Elapsed += new System.Timers.ElapsedEventHandler(Time); t.Interval = 1000; t.Start(); Thread.Sleep(3000); new Rush(TheWorld).BeginInvoke(null, null); for (int i = 0; i < 23; ++i) new Rush(Muda).BeginInvoke(null, null); // こっちだと時は止まりません // new Thread(new ThreadStart(Muda)).Start(); IAsyncResult result = new Rush(Mudaa).BeginInvoke(null, null); result.AsyncWaitHandle.WaitOne(); Thread.Sleep(1000); } } /* 2006/01/23 22:43:16 2006/01/23 22:43:17 ザ・ワールド!! 時よ止まれ! 無駄無駄(以下略)無駄ァ!!!! そして時は動き出す 2006/01/23 22:43:31 (以下略) 2006/01/23 22:43:32 */
上記を見ての通り、大量にBeginInvokeを行うとTimers.Elapsedが影響を受けます。実はBeginInvokeもElapsedもスレッドプールを使用していて、デフォルトで1CPU、1プロセスあたり25スレッドという制限があるためです。なので、BeginInvokeには時間の掛かる処理は行わせるべきではありません。ちなみにコメントアウトしているThreadを使った処理の場合は、スレッドプールを使わないので時は止まりません。(^^;