ASP.NET - 非同步處理 (一)

  • 5350
  • 0

此篇簡單介紹執行緒(Thread)。

此篇程式都運行在同一個主程式內,若要個別瞭解只需註解掉主程式內的程式碼。


 

主程式 : 

using System;
using System.Threading;

namespace TreadDay1
{
    //底下是個測試多執行緒的簡單範例,示範如何建立一個執行緒來執行某件背景工作。有個名詞得先說一下:
    //    負責執行背景工作的執行緒又稱為「工作執行緒」(worker thread)。之所以不說「背景執行緒」,
    //    是為了避免跟執行緒集區有關的前景、背景執行緒概念混淆。
    class Program
    {
        static void Main(string[] args)
        {
            // 指定方法建立執行緒
            Thread t1 = new Thread(MyBackgroundTask);
            Thread t2 = new Thread(MyBackgroundTask);
            Thread t3 = new Thread(MyBackgroundTask);
            
            // 啟動執行緒 若沒有特殊處理執行續會自動被終止或釋放
            t1.Start();
            t2.Start();
            t3.Start();
            
            // 等待執行緒結束 Main主程序執行到這行會等待t1執行緒執行完畢後才繼續往下
            // 但其它執行緒Tread不受到此指令引響
            t1.Join();

            // 讓目前執行緒休息
            Thread.Sleep(1);

            for (int i = 0; i < 500; i++)
            {
                Console.Write(".");
            }

            Console.WriteLine();

            // 不同執行緒共享變數
            new SharedStateDemo().Run();

            // 使用Lock鎖定執行緒來執行
            new Locker().Run();

            // 使用無窮迴圈測試背景執行緒
            new Background().Run();

            // 使用.NET 所提供靜態方法 CLR執行緒集區 由CLR來幫忙管理執行緒
            ThreadPool.QueueUserWorkItem(DownloadFile,"xyz.iso");

            Console.ReadLine();
        }

        static void MyBackgroundTask()
        {
            for (int i = 0; i < 500; i++)
            {
                Console.Write("[" + Thread.CurrentThread.ManagedThreadId + "]");
            }
        }
        
        static void DownloadFile(object fileName)
        {
            Console.WriteLine("Downloading file {0}", fileName);
        }
    }
}

 

不同執行緒共享變數的類 : SharedStateDemo.cs

using System;
using System.Threading;

namespace TreadDay1
{
    class SharedStateDemo
    {
        private int _itemcount = 0;   // 已加入購物車的商品數量。

        public void Run()
        {
            var t1 = new Thread(this.AddToCart);
            var t2 = new Thread(this.AddToCart);

            t1.Start(300);
            t2.Start(100);
            //如果 t1 和 t2 這兩條執行緒是依照它們啟動的順序先後完成任務,執行結果的第一列顯示地購物車商品數量應為 1,
            //第二列的數量才是 2。可是現在卻全都是 2,這是因為 t1 先啟動,進入 AddCart 函式之後,把 itemCount 加一,
            //然後進入一段模擬長時間工作的延遲(300ms)。此時 t2 也已經啟動了,也把 itemCount 加一了(其值為 2),
            //然後也進入一段延遲(100ms)。但由於 t2 的延遲時間較短,比 t1 更快執行完畢(後發而先至),
            //因此執行結果畫面中的第一列文字其實是由執行緒 t2 輸出的。接下來,t1 也跑完了,但此時的 itemCount 已經被 t2 改成了 2,
            //所以輸出的結果自然就一樣了。
        }

        private void AddToCart(object simulateDelay)
        {
            this._itemcount++;

            /*
             * 用 Thread.Sleep 來模擬這項工作所花的時間,時間長短
             * 由呼叫端傳入的 simulateDelay 參數指定,以便藉由改變
             * 此參數來觀察共享變數值的變化。
             */
            Thread.Sleep((int)simulateDelay);
            Console.WriteLine("Items in cart: {0}", _itemcount);
        }

    }
}

 

使用Lock鎖定執行緒來執行 : Locker.cs

using System;
using System.Threading;

namespace TreadDay1
{
    class Locker
    {
        private int _itemcount = 0;
        private object _locker = new Object(); // 用於獨佔鎖定的物件

        public void Run()
        {
            var t1 = new Thread(AddToCart);
            var t2 = new Thread(AddToCart);

            t1.Start(300);
            t2.Start(100);
        }

        private void AddToCart(object simulateDelay)
        {
            Console.WriteLine("Enter thread {0}", // 顯示目前所在的執行緒編號
                Thread.CurrentThread.ManagedThreadId);
            lock (this._locker)  // 利用 locker 物件來鎖定程式區塊
            {
                this._itemcount++;

                Thread.Sleep((int)simulateDelay);
                Console.WriteLine("Items in cart: {0} on thread {1}",
                    this._itemcount, Thread.CurrentThread.ManagedThreadId);
            }
        }
    }
}

 

使用無窮迴圈測試背景執行緒 : Background.cs

using System;
using System.Threading;

namespace TreadDay1
{
    //背景執行緒
    class Background
    {
        public int MyProperty { get; set; }

        public void Run()
        {
            Thread t = new Thread(MyWork);
            t.IsBackground = true;
            t.Start();
            Console.WriteLine("IsBackground");
            // 若 t 是前景執行緒,此應用程式不會結束,除非手動將它關閉;
            // 若 t 是背景執行緒,此應用程式會立刻結束。
        }

        static void MyWork()
        {
            while (true)
                ;
        }
    }
}

 

 


多多指教!! 歡迎交流!!

你不知道自己不知道,那你會以為你知道