第一節:復習委托,並且通過委托的異步調用開啟一個新線程和異步回調、異步等待。


一. 再談委托

1. 委托是一個關鍵字為delegate的自定義類型,通過委托可以把方法以參數的形式傳遞給另外一個方法,實現插件式的開發模式;

    同時調用委托的時候,委托所包含的所有方法都會被實現。

2. 委托的發展歷史:new實例化傳遞方法→直接等於方法名→delegate匿名方法→省略delegate→省略括號中的參數→當只有一個參數省略小括號

          →當方法體只有一行,省略大括號

 (詳見:http://www.cnblogs.com/yaopengfei/p/6959141.html)

3:常用的Action委托和Func委托

  A. Action<>委托,無返回值,至少有一個參數的委托

  B. Func<>委托,有返回值,可以無參數的委托(當然也可以有參數)

  C. Action委托,無參數無返回值的委托 

二. 委托的調用

委托的調用分為兩種:

  A. 同步調用:Invoke方法,方法參數為函數的參數。

  B. 異步調用:BeginInvoke方法。

其中無論是哪類調用,都有兩類寫法:

  ①:利用Action<>(或Func<>)內置委托,調用的時候賦值。

  ②:利用Action委托,直接賦值,然后調用。

 1         /// <summary>
 2         /// 執行動作:耗時而已
 3         /// </summary>
 4         private void TestThread2(string threadName1, string threadName2)
 5         {
 6             Console.WriteLine("線程開始:線程名為:{2}和{3},當前線程的id為:{0},當前時間為:{1},", System.Threading.Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff"), threadName1, threadName2);
 7             long sum = 0;
 8             for (int i = 1; i < 999999999; i++)
 9             {
10                 sum += i;
11             }
12             Console.WriteLine("線程結束:線程名為:{2}和{3},當前線程的id為::{0},當前時間為:{1}", System.Threading.Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff"), threadName1, threadName2);
13         }

 

 

 

 

 

 

 

三. 深入剖析BeginInvoke方法

   首先需要明確,該方法參數個數不定, 最后兩個參數含義固定,如果不使用的話,需要賦值null;該方法最少兩個參數,即方法無參數,這種情況下BeginInvoke中只有兩個參數。此外,賦值的方法有幾個參數,BeginInvoke中從左開始,新增幾個參數。

  ①. 倒數第二個參數:是有一個參數值無返回值的委托,它代表的含義為,該線程執行完畢后的回調。

  ②. 倒數第一個參數:向倒數第二個參數(即回調)中傳值,需要用AsyncState來接受。

  ③. 其它參數:即為賦值方法的參數。

注:BeginInvoke的返回值等價於異步回調中的t。

 1   private void button13_Click(object sender, EventArgs e)
 2         {
 3             Stopwatch watch = new Stopwatch();
 4             watch.Start();
 5             Console.WriteLine("----------------- button1_Click 開始 主線程id為:{0}  --------------------------", Thread.CurrentThread.ManagedThreadId);
 6 
 7             Action<string> myFunc = this.TestThread;
 8             IAsyncResult asyncResult = null;
 9             //參數說明:前面幾個參數都是方法的參數值,倒數第二個為異步調用的回調函數,倒數第一個為傳給回調函數的參數
10             for (int i = 0; i < 1; i++)
11             {
12                 string name = string.Format("button1_Click{0}", i);
13                 asyncResult = myFunc.BeginInvoke(name, t =>
14                    {
15                        Console.WriteLine("我是線程{0}的回調", Thread.CurrentThread.ManagedThreadId);
16                        //用 t.AsyncState 來獲取回調傳進來的參數
17                        Console.WriteLine("傳進來的參數為:{0}", t.AsyncState);
18 
19                        //測試一下異步返回值的結果
20                        Console.WriteLine("異步返回值的結果:{0}", t.Equals(asyncResult));
21                    }, "maru");
22             }
23 
24             watch.Stop();
25             Console.WriteLine("----------------- button1_Click 結束 主線程id為:{0}  總耗時:{1}--------------------------", Thread.CurrentThread.ManagedThreadId, watch.ElapsedMilliseconds);
26 
27         }

結果:

 

四. 線程等待的三種方式

1. asyncResult.IsCompleted屬性,該方式會存在時間上的誤差。

2. WaitOne方法,可以控制一直等待or超時不再等待。

3. EndInvoke方法,官方推薦的線程等待的方式。

以上三種方式的局限性:批量線程等待的時候,不靈活,需要for循環了。

 1   private void button14_Click(object sender, EventArgs e)
 2         {
 3             Stopwatch watch = new Stopwatch();
 4             watch.Start();
 5             Console.WriteLine("----------------- button1_Click 開始 主線程id為:{0}  --------------------------", Thread.CurrentThread.ManagedThreadId);
 6 
 7             IAsyncResult asyncResult = null;
 8             Action<string> myFunc = this.TestThread;
 9             string name = string.Format("button1_Click{0}", 111);
10             asyncResult = myFunc.BeginInvoke(name, t =>
11              {
12                  Console.WriteLine("我是線程{0}的回調", Thread.CurrentThread.ManagedThreadId);
13                  //用 t.AsyncState 來獲取回調傳進來的參數
14                  Console.WriteLine("傳進來的參數為:{0}", t.AsyncState);
15              }, "maru");
16 
17             //等待的方式1:會有時間上的誤差
18             //while (!asyncResult.IsCompleted)
19             //{
20             //    Console.WriteLine("正在等待中");
21             //}
22 
23             // 等待的方式二:
24             //asyncResult.AsyncWaitHandle.WaitOne();//一直等待
25             //asyncResult.AsyncWaitHandle.WaitOne(-1);//一直等待
26             //asyncResult.AsyncWaitHandle.WaitOne(1000);//等待1000毫秒,超時就不等待了
27 
28             //等待的方式三:
29             myFunc.EndInvoke(asyncResult);
30 
31             watch.Stop();
32             Console.WriteLine("----------------- button1_Click 結束 主線程id為:{0}  總耗時:{1}--------------------------", Thread.CurrentThread.ManagedThreadId, watch.ElapsedMilliseconds);
33 
34         }

下面是多個線程等待的情況:

 1   private void button15_Click(object sender, EventArgs e)
 2         {
 3             Stopwatch watch = new Stopwatch();
 4             watch.Start();
 5             Console.WriteLine("----------------- button1_Click 開始 主線程id為:{0}  --------------------------", Thread.CurrentThread.ManagedThreadId);
 6 
 7             List<IAsyncResult> list = new List<IAsyncResult>();
 8 
 9             for (int i = 0; i < 5; i++)
10             {
11                 string name = string.Format("button1_Click{0}", i);
12                 Action myFunc = () =>
13                 {
14                     TestThread2(name, name);
15                 };
16                 var asyncResult = myFunc.BeginInvoke(null, null);
17                 list.Add(asyncResult);
18             }
19 
20             //下面是線程等待
21             foreach (var item in list)
22             {
23                 item.AsyncWaitHandle.WaitOne(-1);
24             }
25 
26             watch.Stop();
27             Console.WriteLine("----------------- button1_Click 結束 主線程id為:{0}  總耗時:{1}--------------------------", Thread.CurrentThread.ManagedThreadId, watch.ElapsedMilliseconds);
28         }

結果:

 

 

!

  • 作       者 : Yaopengfei(姚鵬飛)
  • 博客地址 : http://www.cnblogs.com/yaopengfei/
  • 聲     明1 : 本人才疏學淺,用郭德綱的話說“我是一個小學生”,如有錯誤,歡迎討論,請勿謾罵^_^。
  • 聲     明2 : 原創博客請在轉載時保留原文鏈接或在文章開頭加上本人博客地址,否則保留追究法律責任的權利。
 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM