這幾天,看WF本質論,裡面提到了.net的異步處理。由於裡面使用的是代碼片段,所以有點看不懂。於是下定決心,溫習一下.net中的異步處理。
使用C#在.net開發已經有5年了,最初使用.net中的異步處理大約是在4年前。當時,只是為了實現要求的功能,沒有詳細研究。這也難怪看WF時會頭暈(基礎不牢的後果呀)。
首先,我們分析一下異步處理的環境
1. 需要在當前線程中獲取返回值
2. 不需要在當前線程中獲取返回值,但是仍然需要對返回值做處理
對於第1中情況,還可以繼續細分
1. 在當前線程中啟動線程T,然後繼續執行當前線程中的其它任務,最後在當前線程中獲取T的返回值
2. 在當前線程中啟動線程T,然後繼續執行當前線程中的其它任務R1,等待T執行完成,當T執行完成後,繼續執行當前線程中的其它任務R2,最後獲取T的返回值
3. 在當前線程中啟動線程T,只要T在執行就執行任務R,最後獲取T的返回值
下面,我將一一給出例子:
1.1 在當前線程中啟動線程T,然後繼續執行當前線程中的其它任務,最後在當前線程中獲取T的返回值
01 using System;
02 using System.Collections.Generic;
03 using System.Linq;
04 using System.Windows.Forms;
05 using System.Threading;
06 using System.Runtime.Remoting.Messaging;
07 namespace FirstWF
08 {
09 static class Program
10 {
11 /// <summary>
12 /// The main entry point for the application.
13 /// </summary>
14 [STAThread]
15 static void Main()
16 {
17 AsyncFuncDelegate caller = new AsyncFuncDelegate(Func);
18 Console.WriteLine("Input number please...");
19 IAsyncResult result = caller.BeginInvoke(Convert.ToInt32(Console.ReadLine()), null, null);
20 Console.WriteLine("Implement other tasks");
21 Thread.Sleep(7000);
22 Console.WriteLine("Implement other tasks end ...");
23 Console.WriteLine("Get user's input");
24 Console.WriteLine(caller.EndInvoke(result));
25 Console.ReadLine();
26 }
27 delegate string AsyncFuncDelegate(int userInput);
28 static string Func(int userInput)
29 {
30 Console.WriteLine("Func start to run");
31 Console.WriteLine("...");
32 Thread.Sleep(5000);
33 Console.WriteLine("Func end to run");
34 return userInput.ToString();
35 }
36 }
37 }
輸出結果如下:
Implement other tasks
Func start to run
...
Func end to run
Implement other tasks end ...
Get user's input
56
1.2 在當前線程中啟動線程T,然後繼續執行當前線程中的其它任務R1,等待T執行完成,當T執行完成後,繼續執行當前線程中的其它任務R2,最後獲取T的返回值
01 static void Main()
02 {
03 AsyncFuncDelegate caller = new AsyncFuncDelegate(Func);
04 Console.WriteLine("Input number please...");
05 IAsyncResult result = caller.BeginInvoke(Convert.ToInt32(Console.ReadLine()), null, null);
06 Console.WriteLine("Implement task 1");
07 result.AsyncWaitHandle.WaitOne();
08 result.AsyncWaitHandle.Close();
09 Console.WriteLine("Implment task 2");
10 Console.WriteLine("Get user's input");
11 Console.WriteLine(caller.EndInvoke(result));
12 Console.ReadLine();
13 }
輸出結果如下:
Input number please...
25
Implement task 1
Func start to run
...
Func end to run
Implment task 2
Get user's input
25
1.3 在當前線程中啟動線程T,只要T在執行就執行任務R,最後獲取T的返回值
01 [STAThread]
02 static void Main()
03 {
04 AsyncFuncDelegate caller = new AsyncFuncDelegate(Func);
05 Console.WriteLine("Input number please...");
06 IAsyncResult result = caller.BeginInvoke(Convert.ToInt32(Console.ReadLine()), null, null);
07 while (!result.IsCompleted)
08 {
09 Thread.Sleep(1000);
10 Console.Write(">");
11 }
12 Console.WriteLine("");
13 Console.WriteLine("Implement other task2");
14 Console.WriteLine("Get user's input");
15 Console.WriteLine(caller.EndInvoke(result));
16 Console.ReadLine();
17 }
輸出結果如下:
Func start to run
...
>>>>>Func end to run
>
Implement other task2
Get user's input
23
2 不需要在當前線程中獲取返回值,但是仍然需要對返回值做處理
01 using System;
02 using System.Collections.Generic;
03 using System.Linq;
04 using System.Windows.Forms;
05 using System.Threading;
06 using System.Runtime.Remoting.Messaging;
07 namespace FirstWF
08 {
09 static class Program
10 {
11 /// <summary>
12 /// The main entry point for the application.
13 /// </summary>
14 [STAThread]
15 static void Main()
16 {
17 AsyncFuncDelegate caller = new AsyncFuncDelegate(Func);
18 Console.WriteLine("Input number please...");
19 caller.BeginInvoke(Convert.ToInt32(Console.ReadLine()), new AsyncCallback(CallBackFunc), "Message from Main thread.");
20 Console.WriteLine("Main thread ends");
21 Console.ReadLine();
22 }
23 delegate string AsyncFuncDelegate(int userInput);
24 static string Func(int userInput)
25 {
26 Console.WriteLine("Func start to run");
27 Console.WriteLine("...");
28 Thread.Sleep(5000);
29 Console.WriteLine("Func end to run");
30 return userInput.ToString();
31 }
32 static void CallBackFunc(IAsyncResult ar)
33 {
34 AsyncResult result = ar as AsyncResult;
35 string inputMessage = result.AsyncState as string;
36 AsyncFuncDelegate caller = result.AsyncDelegate as AsyncFuncDelegate;
37 Console.WriteLine("call back starts");
38 Console.WriteLine(inputMessage);
39 Console.WriteLine("The input number is : " + caller.EndInvoke(ar));
40 Console.WriteLine("call back ends");
41 }
42 }
43 }
輸出結果如下:
Input number please...
23
Main thread ends
Func start to run
...
Func end to run
call back starts
Message from Main thread.
The input number is : 23
call back ends
記得以前的代碼,寫的都不是很好。雖然call.BeginInvoke可以開始異步調用,但幾乎就沒有使用過EndInvoke。EndInvoke可以保證異步調用被正常結束,使代碼更加健康。
異步調用,可以使代碼具有更高的執行效率,但是在異步調用時,應該有一個健康的使用習慣。