天天看點

BeginInvoke、ThreadPool、Task三類異步方法的差別和速度比較

速度(最快為1) 傳回值 多參數 等待在時限内完成 逾時後結束
ThreadPool.UnsafeQueueUserWorkItem() 1 非原生支援1 非原生支援 非原生支援3 不支援
ThreadPool.QueueUserWorkItem() 2.7 非原生支援1 非原生支援 非原生支援3 不支援
Task() 4.5 支援2 非原生支援 支援 自願結束
Delegate.BeinInvoke() 25.4 非原生支援1 支援 支援4 不支援
Thread.Start() 11009 非原生支援1 非原生支援 非原生支援3 支援
  1. 如ThreadPool.UnsafeQueueUserWorkItem(()=>result=Add(1,2));
  2. 用Task<>
  3. 裡面在程式末尾EventWaitHandle.Set(),外面WaitOne(TimeSpan)。
  4. 獲得BeginInvoke的傳回值asyncResult,再調asyncResult.AsyncWaitHandle.WaitOne();

有圖有真相。這是各種異步方法循環調用N次所需的時間。

代碼如下:

static void Main(string[] args)
        {
            Action threadStart = (() => { });
            WaitCallback waitCallback = new WaitCallback(a => { });
            Stopwatch stopWatch = new Stopwatch();

            stopWatch.Reset();
            stopWatch.Start();
            for (int i = 0; i < 10000; i++)
            {
                System.Threading.ThreadPool.UnsafeQueueUserWorkItem(waitCallback, null);
            }
            stopWatch.Stop();
            Console.WriteLine("{0,-40}{1}", "ThreadPool.UnsafeQueueUserWorkItem():", stopWatch.ElapsedTicks);
            GC.Collect();

            stopWatch.Reset();
            stopWatch.Start();
            for (int i = 0; i < 10000; i++)
            {
                System.Threading.ThreadPool.QueueUserWorkItem(waitCallback);
            }
            stopWatch.Stop();
            Console.WriteLine("{0,-40}{1}", "ThreadPool.QueueUserWorkItem():", stopWatch.ElapsedTicks);
            GC.Collect();

            stopWatch.Reset();
            stopWatch.Start();
            for (int i = 0; i < 10000; i++)
            {
                Task t = new Task(threadStart);
                t.Start();
            }
            stopWatch.Stop();
            Console.WriteLine("{0,-40}{1}", "Task():", stopWatch.ElapsedTicks);
            GC.Collect();

            stopWatch.Reset();
            stopWatch.Start();
            for (int i = 0; i < 10000; i++)
            {
                threadStart.BeginInvoke(null, null);
            }
            stopWatch.Stop();
            Console.WriteLine("{0,-40}{1}", "Delegate.BeinInvoke():", stopWatch.ElapsedTicks);

        }      

注意,上面BeginInvoke的用法并不完整,應當再調用EndInvoke。但是鑒于BeginInvoke已經最慢了,EndInvoke便不加了。

是以,如果無需傳回值,一般就用ThreadPool吧,要更多控制,就Task。鄙人想不到用BeginInvoke的時機。