32

在 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 确保线程池中的一个线程用于执行异步代码,那么有什么区别吗?

4

1 回答 1

34

乔·达菲( Joe Duffy)在他的Concurrent Programming on Windows书中(第 418 页)这样说Delegate.BeginInvoke

按照惯例,所有委托类型都提供 BeginInvoke 和EndInvoke方法以及普通同步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);
});

将运行时间更改为 864 毫秒。

于 2012-04-26T20:47:35.730 回答