生活随笔
收集整理的這篇文章主要介紹了
浅谈C#中的异步编程
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
實現異步編程有4種方法可供選擇,這4種訪求實際上也對應著4種異步調用的模式,分為“等待”和“回調”兩大類。
Title一、使用EndInvoke;
二、使用WaitHanle;
三、輪詢;
四、回調。
一、使用EndInvoke
當使用BeginInvoke異步調用方法時,如果方法未執行完,EndInvoke方法就會一直阻塞,直到被調用的方法執行完畢,如下面的代碼:
Ellic's Code
1 using System;2 using System.Threading;3 namespace MetadataSample4 {5 class Program6 {7 //聲明一個委托類型8 public delegate void PrintDelegate(
string content);9 public static void Main(
string[] args)10 {11 int threadId =
Thread.CurrentThread.ManagedThreadId;12 PrintDelegate printDelegate =
Program.Print;13 Console.WriteLine(
"[主線程id:{0}]\t開始調用打印方法...",threadId);14 IAsyncResult result = printDelegate.BeginInvoke(
"Hello world",
null,
null);15 printDelegate.EndInvoke(result);1617 Console.Write(
"Press any key to continue . . . ");18 Console.ReadKey(
true);19 }20 public static void Print(
string content)21 {22 int threadId=
Thread.CurrentThread.ManagedThreadId;23 Console.WriteLine(
"[當前線程id:{0}]\t{1}",threadId,content);24 System.Threading.Thread.Sleep(
2000);25 Console.WriteLine(
"[當前線程id:{0}]\t打印方法調用完畢.",threadId);26 }27 }28 }
?
知識點回顧:
1、委托類型
委托類似于C/C++中的函數指針,它能夠引用函數,只不過在C#中,委托是一個對象,并且是類型安全的,避免了函數指針的不安全性。一個委托類型的變量可以引用一個或多個方法,這些方法由委托存放于一個調用列表中,當調用一個委托類型的變量即相當于依次調用它的“調用列表”中的方法。委托是一種引用類型。
可以被引用的方法必須要滿足如下規則:
Θ方法的簽名和委托一致,比如方法參數的個數和類型;
Θ方法的返回值和委托一致。
委托的聲明與實例化:
Ellic's Code
1 using System;2 namespace DelegateSample3 {4 public delegate void DoProcess(
string msg);5 class DelegateSample6 {7 void Process(
string msg)8 {9 Console.WriteLine(
"Process:{0}",msg );10 }11 public static void Main(
string[] args)12 {13 DelegateSample sample =
new DelegateSample();14 DoProcess process =
new DoProcess(sample.Process);15 //DoProcess process = sample.Process;16 process(
"測試數據");17 Console.Write(
"Press any key to continue . . . ");18 Console.ReadKey(
true);19 }20 }21 }2、IAsyncResult接口IasyncResult接口定義了異步操作狀態應該提供的屬性,它的源代碼如下:1 public interface IAsyncResult2 {3 object AsycState{
get;}4 WaitHandle AsyncWaitHandle{
get;}5 bool CompletedSynchronously{
get;}6 bool IsCompleted{
get;}7 }
?
這些屬性都是只讀屬性,它們的含義如下:
| 屬性 | 返回類型 | 說明 |
| AsycState | object | 此屬性返回一個對象,該對象是啟動異步操作的方法的最后一個參數 |
| AsyncWaitHandle | WaitHandle | 獲取用于等待異步操作完成的WaitHandle |
| CompletedSynchronously | bool | 獲取一個值,該值指示異步操作是否同步完成 |
| IsCompleted | bool | 獲取一個值,該值指示異步操作是否已完成 |
關于IAndsyncResult接口需要補充的是,BeginInvoke方法的返回類型以及EndInvoke方法的唯一參數均為IasyncResult接口類型。
二、使用WaitHandle
除了上面提到的方法,我們還可以使用WainHandle類型的WaitOne方法。WaitOne方法有5個重載:
n bool WaitOne()
n bool WaitOne(int millisecondsTimeout)
n bool WaitOne(TimeSpan timeout)
n bool WaitOne(int millisecondsTimeout, bool exitContext)
n bool WaitOne(TimeSpan timeout,bool exitContext)
其中,第一個不帶參數的重載相當于WaitOne(-1,false),第一個參數表示等待的毫秒數,-1表示無限期等待,第二個參數表示在等待前是否退出上下文的同步域,并在稍后進行重新獲取,是則為TRUE,否則為FALSE。
這些重載的核心實現為第四個重載,其他的重載就是對參數類型或個數的改變。運行代碼如下:
Ellic's Code
1 using System;2 using System.Threading;34 namespace MetadataSample5 {6 class Program7 {8 //聲明一個委托類型9 public delegate void PrintDelegate(
string content);10 public static void Main(
string[] args)11 {12 int threadId =
Thread.CurrentThread.ManagedThreadId;13 PrintDelegate printDelegate =
Program.Print;14 Console.WriteLine(
"[主線程id:{0}]\t開始調用打印方法...",threadId);15 IAsyncResult result = printDelegate.BeginInvoke(
"Hello world",
null,
null);16 //printDelegate.EndInvoke(result);17 result.AsyncWaitHandle.WaitOne(
5000,
false);1819 Console.Write(
"Press any key to continue . . . ");20 Console.ReadKey(
true);21 }22 public static void Print(
string content)23 {24 int threadId=
Thread.CurrentThread.ManagedThreadId;25 Console.WriteLine(
"[當前線程id:{0}]\t{1}",threadId,content);26 System.Threading.Thread.Sleep(
2000);27 Console.WriteLine(
"[當前線程id:{0}]\t打印方法調用完畢.",threadId);28 }29 }30 }可以看到,與EndInvoke類似,只是用WaitOne函數代碼了EndInvoke而已。三、輪詢之前提到的兩種方法,只能等下異步方法執行完畢,在完畢之前沒有任何提示信息,整個程序就像沒有響應一樣,用戶體驗不好,可以通過檢查IasyncResult類型的IsCompleted屬性來檢查異步調用是否完成,如果沒有完成,則可以適時地顯示一些提示信息,如下面的代碼:Ellic's Code1 using System;2 using System.Threading;3 namespace MetadataSample4 {5 class Program6 {7 //聲明一個委托類型8 public delegate void PrintDelegate(
string content);9 public static void Main(
string[] args)10 {11 int threadId =
Thread.CurrentThread.ManagedThreadId;12 PrintDelegate printDelegate =
Program.Print;13 Console.WriteLine(
"[主線程id:{0}]\t開始調用打印方法...",threadId);14 IAsyncResult result = printDelegate.BeginInvoke(
"Hello world",
null,
null);15 while (!
result.IsCompleted)16 {17 Console.WriteLine(
" . ");18 Thread.Sleep(
500);19 }20 Console.Write(
"Press any key to continue . . . ");21 Console.ReadKey(
true);22 }23 public static void Print(
string content)24 {25 int threadId=
Thread.CurrentThread.ManagedThreadId;26 Console.WriteLine(
"[當前線程id:{0}]\t{1}",threadId,content);27 System.Threading.Thread.Sleep(
2000);28 Console.WriteLine(
"[當前線程id:{0}]\t打印方法調用完畢.",threadId);29 }30 }31 }
?
結果如下:
四、回調
之前三種方法者在等待異步方法執行完畢后才能拿到執行的結果,期間主線程均處于等待狀態。回調和它們最大的區別是,在調用BeginInvoke時只要提供了回調方法,那么主線程就不必要再等待異步線程工作完畢,異步線程在工作結束后會主動調用我們提供的回調方法,并在回調方法中做相應的處理,例如顯示異步調用的結果。
先看到之前那段調用BeginInvoke的代碼:
IAsyncResult result = printDelegate.BeginInvoke("Hello world",null,null);
其中,第1個參數是委托簽名中的參數,后面2個參數實際是我們在回調方法中要用到的,它們分別是:
AsyncCallback callback
object @object
前者就是回調方法,它要求回調方法的簽名必須符合以下條件:
返回類型為void;
參數列表只有1個參數,且為IAsyncResult 類型。
如:void callbackMethod(IasyncResult asyncResult)
回調方法代碼如下:
Ellic's Code
1 using System;2 using System.Threading;3 namespace MetadataSample4 {5 class Program6 {7 //聲明一個委托類型8 public delegate void PrintDelegate(
string content);9 public static void Main(
string[] args)10 {11 int threadId =
Thread.CurrentThread.ManagedThreadId;12 PrintDelegate printDelegate =
Program.Print;13 Console.WriteLine(
"[主線程id:{0}]\t開始調用打印方法...",threadId);14 IAsyncResult result = printDelegate.BeginInvoke(
"Hello world",PrintComplete,printDelegate);15 Thread.Sleep(
10000);1617 Console.Write(
"Press any key to continue . . . ");18 Console.ReadKey(
true);19 }20 public static void Print(
string content)21 {22 int threadId=
Thread.CurrentThread.ManagedThreadId;23 Console.WriteLine(
"[當前線程id:{0}]\t{1}",threadId,content);24 System.Threading.Thread.Sleep(
1000);2526 }2728 private static void PrintComplete(IAsyncResult asyncResult)29 {30 if(
null ==
asyncResult)31 {32 throw new ArgumentNullException();33 }34 int threadId =
Thread.CurrentThread.ManagedThreadId;35 (asyncResult.AsyncState
as PrintDelegate).EndInvoke(asyncResult);36 Console.WriteLine(
"[當前線程id:{0}]\t打印方法調用完畢.",threadId);37 }38 }39 }
?
上面的四種方法就是自己在復習C#時學到的新知識,記錄下來。
總結
以上是生活随笔為你收集整理的浅谈C#中的异步编程的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。