異步是一個龐大的話題,但總的來說,我認為它有不阻塞當前請求線程、提高吞吐量等作用。
對於服務端和客戶端互相調用的程序,我認為異步可以分為客戶端異步、服務端異步,並且他們異步操作互不影響。
從是否等待來看,我覺得可以分為等待異步方式和不等待的異步方式。
異步代碼編寫上,主要有兩種方式:APM Asynchronouse Programming Model,EAP Event-base Asynchronous Pattern。它們分別是BeginXXX,EndXXX和基於事件的XXXCompleted,XXXAsync的異步方式。
除了創建線程等方式的異步,如果和CPU並行執行任務,是需要硬件支持的,大多硬件都提供了DMA功能,當硬件在DMA模式下,CPU只須向DMA控制器下達指令,讓DMA控制器來處理數據的傳送,數據傳送完畢再用中斷的方式反饋給CPU,這塊更專業的解釋需要參考其他文章資料。封裝后對於.net程序的異步,一般都是通過回調的方式通知異步完成了。
WebService異步
我認為WebService客戶端異步主要包括如下:
1、
用線程Thread直接開子線程,可以和主調用線程異步執行。
2、
用線程池ThreadPool開后台線程,和主調用線程異步執行。
3、
Begin[WebMethodName]異步調用,End[WebMethodName]方式回調。
4、
[WebMethodName]Completed+=委托回調,[WebMethodName]Async異步方式調用。
對於winform程序,常用的還有BackgroundWorker組件來異步執行任務。
WebService服務端異步主要包括如下:
1、
配置webmethod為One-way方式,即在WebMethod添加屬性為:
[System.Web.Services.Protocols.SoapDocumentMethod(OneWay = true)],對於One-way方式,服務端要求是void返回類型,客戶端調用后就不關心后續執行是否正確或異常了,直接返回客戶端,因此我自己認為可以算服務端配置的一個異步。但經過我的測試,發現One-way方式始終要增加一個windows線程來處理,並且這個線程為1個工作線程,因此最好不要大量使用。
2、
Begin[WebMethodName],End[WebMethodName]方式,服務端配置和客戶端配置不一樣,服務端配置BeginXXX,EndXXX方式,BeginXXX返回IAsyncReSult結果,EndXXX接受IAsyncResult為參數的方法,對於客戶端,同樣需要等待服務端的整個執行流程,唯一的優化是在BeginXXX和EndXXX之間釋放出了一個CLR線程,可以提高並發量。對於回調函數EndXXX,它會根據不同情況占據不同的CLR線程。
3、
服務端自己開子線程,可以立即返回客戶段,也可以用信號量等待服務端執行完畢再返回,或者插入消息隊列等,異步邏輯,因此我覺得泛指的異步是一個大的話題。
WebService引用方式
對於.Net引用webserv ice主要有兩種方式:
1、
Web引用
在.net2.0框架下的項目,右鍵項目,下面即有添加Web引用,如果是高版本框架項目下,在添加服務引用下,進入高級按鈕選項,有添加Web引用的按鈕。如圖:
圖一
實際它內部是通過WSDL.exe程序來引用webservice,但它只能生成基於事件的異步方式,執行命令比如:
wsdl.exe http://localhost:4003/Service1.asmx /out:Service1.cs,執行后如:

圖二
2、
服務引用
它內部通過SvcUtil.exe程序,引用.net2.0后新增的WCF等,兼容以前web服務,比如:
svcutil http://localhost:4003/Service1.asmx /out:service2.cs,執行后如:

圖三
WSDL和SvcUtil程序位於C:\Program Files\Microsoft SDKs\Windows\v6.0A(可能其他版本)\bin目錄下,生成了cs文件后,可以通過:
csc.exe /target:library /out:Service1.dll Service1.cs 來生成對應的dll文件。
但是默認服務引用不會生成異步調用方式,需要在高級里勾選生成異步操作,它會生成基於事件和APM的異步調用方式,如圖:

圖四
異步示例
下面貼下服務端異步方式的示例代碼:
[WebMethod]
public IAsyncResult BeginServerAsyncHelloWorld(string str, AsyncCallback cb, object state)
{
//http://lawson.cnblogs.com
string connectionString = @"Data Source=localhost;User ID=sa;Password=1123;Asynchronous Processing=true";
SqlConnection connection = new SqlConnection(connectionString);
connection.Open();
SqlCommand command = new SqlCommand(sql, connection);
IAsyncResult ir = command.BeginExecuteReader(cb, command, System.Data.CommandBehavior.CloseConnection);
return ir;
}
[WebMethod]
public string EndServerAsyncHelloWorld(IAsyncResult ir)
{
StringBuilder sb = new StringBuilder();
SqlCommand command = (SqlCommand)ir.AsyncState;
省略后面代碼,這里看到BeginXXX和EndXXX屬性方法字段都有制定格式,比如begin里后面兩個為:AsyncCallback cb, object state,分別為回調函數和主調函數和回調函數之間的傳地址,比如這里傳遞的是SqlCommand。並且對於客戶端,它發現的方法只為ServerAsyncHelloWorld了。
從上面代碼可以看出,WebService服務端異步只是一個殼子,具體怎么異步還需要內部的內容執行異步調用。如果WebMethod不標注為異步調用方式,內部調用異步代碼,實際請求會消耗更多的CLR線程來執行異步,或造成請求線程的阻塞等待。
對於回調函數,比如ADO.NET操作它會占用1個工作線程,但對於委托異步Remoting等會占用1個IO線程,如需要對線程更好控制的情境,需要注意這些地方。
雖然服務端用了異步方式,對於客戶端,同樣可以再繼續異步,它們互不影響,比如可以用基於事件異步,或APM方式的異步調用服務端異步方法。
最后,對於WebService服務端異步方式,服務端可以操作基於IOCP的異步調用方式,異步過程中節約線程,提供並發量。對於客戶端異步方式,可以不阻塞主線程,提高用戶體現等。
本文是自己對WebService異步的一些總結,如有不對,歡迎指正。