web-dev-qa-db-ja.com

デリゲート.BeginInvokeとC#でのThreadPoolスレッドの使用の違い

C#では、デリゲートを使用して非同期にいくつかの作業(BeginInvoke()を呼び出す)と以下に示すようにThreadPoolスレッドを使用することの間に違いがあります

public void asynchronousWork(object num)
    {
        //asynchronous work to be done
        Console.WriteLine(num);
    }

 public void test()
    {
        Action<object> myCustomDelegate = this.asynchronousWork;
        int x = 7;

        //Using Delegate
        myCustomDelegate.BeginInvoke(7, null, null);

        //Using Threadpool
        ThreadPool.QueueUserWorkItem(new WaitCallback(asynchronousWork), 7);
        Thread.Sleep(2000);
    }

編集:
BeginInvokeは、スレッドプールのスレッドを使用して非同期コードを実行することを確認します。違いはありますか?

31
nighthawk457

ジョー・ダフィ、彼のConcurrent Programming on Windows本(418ページ)、これについてDelegate.BeginInvoke

すべてのデリゲートタイプは、慣例により、通常の同期EndInvokeメソッドに加えてBeginInvokeおよびInvokeメソッドを提供します。これは素晴らしいプログラミングモデルの機能ですが、可能な限りそれらから遠ざける必要があります。実装は、非同期呼び出しにかなりのオーバーヘッドを課すリモート処理インフラストラクチャを使用します。多くの場合、スレッドプールに直接キュー作業を行う方が適切なアプローチですが、ランデブーロジックを自分で調整する必要があります。

編集:相対オーバーヘッドの次の簡単なテストを作成しました:

int counter = 0;
int iterations = 1000000;
Action d = () => { Interlocked.Increment(ref counter); };

var stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start();
for (int i = 0; i < iterations; i++)
{
    var asyncResult = d.BeginInvoke(null, null);
}

do { } while(counter < iterations);
stopwatch.Stop();

Console.WriteLine("Took {0}ms", stopwatch.ElapsedMilliseconds);
Console.ReadLine();

私のマシンでは、上記のテストは約20秒で実行されます。 BeginInvoke呼び出しを

System.Threading.ThreadPool.QueueUserWorkItem(state =>
{
    Interlocked.Increment(ref counter);
});

実行時間を864msに変更します。

33
Lee