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を使った処理の場合は、スレッドプールを使わないので時は止まりません。(^^;