.net 的非同步編程技術主要分為兩個塊:
1、使用IAsyncResult 的非同步編程模式。
2、基於事件的非同步編程模式。
C#編譯器會為每個委託產生支援非同步執行的 BeginInvoke / EndInvoke 方法,從而將委託和非同步編程緊密聯絡起來了。
當同步執行程式時,如果執行到需要執行較長時間的代碼時,使用者必須等待,也會認為程式已經卡死或死機了。
同步程式的範例程式碼如下:
namespace CalculateFolderSizeNoAsync
{
class Program
{
//計算指定檔案夾的總容量
private static long CalculateFolderSize(string FolderName)
{
if (Directory.Exists(FolderName) == false)
{
throw new DirectoryNotFoundException("檔案夾不存在");
}
DirectoryInfo RootDir = new DirectoryInfo(FolderName);
//擷取所有的子檔案夾
DirectoryInfo[] ChildDirs = RootDir.GetDirectories();
//擷取當前檔案夾中的所有檔案
FileInfo[] files = RootDir.GetFiles();
long totalSize = 0;
//累加每個檔案的大小
foreach (FileInfo file in files)
{
totalSize += file.Length;
}
//對每個檔案夾執行同樣的計算過程:累加其下每個檔案的大小
//這是通過遞迴調用實現的
foreach (DirectoryInfo dir in ChildDirs)
{
totalSize += CalculateFolderSize(dir.FullName);
}
//返迴文件夾的總容量
return totalSize;
}
static void Main(string[] args)
{
long size;
string FolderName;
Console.WriteLine("請輸入檔案夾名稱(例如:C:\\Windows):");
FolderName = Console.ReadLine();
size = CalculateFolderSize(FolderName);
Console.WriteLine("\n檔案夾{0}的容量為:{1}位元組\n", FolderName , size);
Console.ReadKey();
}
}
}
程式中調用了CalculateFolderSize方法,如果此方法不返回,下面的代碼是不可能執行的。
如果這個方法執行時間很長,則使用者在方法返回前是看不到任何資訊的,他有可能會以為電腦死機了。
上述程式就是典型的程式同步執行模式。
能不能在調用方法後,不用等待方法執行完成就馬上執行下一條語句?
要實現 這個功能,就必須採用“非同步編程模式”
如下程式碼範例:
namespace AsyncCalculateFolderSize1
{
class Program
{
//計算指定檔案夾的總容量
private static long CalculateFolderSize(string FolderName)
{
if (Directory.Exists(FolderName) == false)
{
throw new DirectoryNotFoundException("檔案夾不存在");
}
DirectoryInfo RootDir = new DirectoryInfo(FolderName);
//擷取所有的子檔案夾
DirectoryInfo[] ChildDirs = RootDir.GetDirectories();
//擷取當前檔案夾中的所有檔案
FileInfo[] files = RootDir.GetFiles();
long totalSize = 0;
//累加每個檔案的大小
foreach (FileInfo file in files)
{
totalSize += file.Length;
}
//對每個檔案夾執行同樣的計算過程:累加其下每個檔案的大小
//這是通過遞迴調用實現的
foreach (DirectoryInfo dir in ChildDirs)
{
totalSize += CalculateFolderSize(dir.FullName);
}
//返迴文件夾的總容量
return totalSize;
}
//定義一個委託
public delegate long CalculateFolderSizeDelegate(string FolderName);
static void Main(string[] args)
{
//定義一個委託變數引用靜態方法CalculateFolderSize
CalculateFolderSizeDelegate d = CalculateFolderSize;
Console.WriteLine("請輸入檔案夾名稱(例如:C:\\Windows):");
string FolderName = Console.ReadLine();
//通過委託非同步呼叫靜態方法CalculateFolderSize
IAsyncResult ret=d.BeginInvoke(FolderName,null,null);
Console.WriteLine("正在計算中,請耐心等待……");
//阻塞,等到調用完成,取出結果
long size = d.EndInvoke(ret);
Console.WriteLine("\n計算完成。檔案夾{0}的容量為:{1}位元組\n", FolderName, size);
Console.ReadKey();
}
}
}
本樣本的非同步編程方式是通過委託來實現的。
通過建立一個引用靜態方法CalculateFolderSize 的委託變數d,第4句通過調用委派物件d 的 BeginInvoke 方法間接地調用靜態方法CalculateFolderSize 不在主線程中執行
,而在另一個輔助純種中與主線程代碼並行 執行,由於存在兩個並行的線程,所以啟動執行靜態方法CalculateFilderSize 之後,並不會等待其完成,而是馬上執行下一句,輸
出一句提示資訊。
從這個典型的非同步呼叫程式中,可以知道非同步呼叫 的一種通用的編程模式是:
//..............
//普通的代碼:處於同步執行模式
IAsyncResult ret = 委託變數.BeginInvoke(......); //啟動非同步呼叫
//可以在這一部分做其他一些事,程式處於非同步執行模式
用於儲存方法結果的變數 = 委託變數.EndInvoke(ret); //結束非同步呼叫
//普通的代碼:處於同步執行模式
//...............