ADO.NET2.0 异步处理的三种方式-wait方法
Wait方法是三种异步调用方法中最为优雅的一种,这种方法提供了高度的灵活性,高效性,当然也稍微复杂一点。使用这种方法可以开始多个异步过程然后等待其中任何或者过程调用结束。使用这种方法你可以只等待那些相互依赖的过程,处理那些不和其他过程依赖的异步过程。这种方法在设计上要求考虑异步过程的细节,你必须慎重判断哪些异步过程是相互依赖的,哪些不是。这种方法的复杂性在于你必须理解其细节并且做出对应的设计。这是一种最好的使用异步调用和异步处理模型的代码设计。注意使用WaitHandle类的WaitOne方法来等待异步过程的执行结束。
<%@ Page Language=”C#” %>
<%@ Import Namespace=”System.Data” %>
<%@ Import Namespace=”System.Data.SqlClient” %>
<%@ Import Namespace=”System.Configuration” %>
<script runat=”server”>
protected void Page_Load(object sender, EventArgs e)
{
SqlConnection DBCon;
SqlCommand Command = new SqlCommand();
SqlDataReader OrdersReader;
IAsyncResult ASyncResult;
System.Threading.WaitHandle WHandle;
DBCon = new SqlConnection();
DBCon.ConnectionString =
ConfigurationManager.ConnectionStrings[“DSN_NorthWind”].ConnectionString;
Command.CommandText =
“SELECT TOP 5 Customers.CompanyName, Customers.ContactName, “ +
“ Orders.OrderID, Orders.OrderDate, “ +
“ Orders.RequiredDate, Orders.ShippedDate “ +
“ FROM Orders, Customers “ +
“ WHERE Orders.CustomerID = Customers.CustomerID “ +
“ ORDER BY Customers.CompanyName, Customers.ContactName “;
Command.CommandType = CommandType.Text;
Command.Connection = DBCon;
DBCon.Open();
// Starting the asynchronous processing
ASyncResult = Command.BeginExecuteReader();
WHandle = ASyncResult.AsyncWaitHandle;
if (WHandle.WaitOne() == true)
{
// Retrieving result from the asynchronous process
OrdersReader = Command.EndExecuteReader(ASyncResult);
// Displaying result on the screen
gvOrders.DataSource = OrdersReader;
gvOrders.DataBind();
// Closing connection
DBCon.Close();
}
else
{
// Asynchronous process has timed out. Handle this
// situation here.
}
}
</script>
如果你设置断点跟踪代码会发现程序在停在调用WHandle.WaitOne方法的那行代码上。当异步调用结束后程序会继续执行。
使用多个Wait句柄
Wait方法在开始多个异步过程的时候其真正威力才能显示出来。其中一个过程查询数据库一个具体的customer的相关信息,另一个查询则处理这个customer提交的所有Order(订单)。下面的代码使用了两个Command对象,data reader对象和wait句柄。这里使用一个connection对象,由此可以看出多活动结果集(MARS)对异步处理的良好支持。
<%@ Import Namespace=”System.Data” %>
<%@ Import Namespace=”System.Data.SqlClient” %>
<%@ Import Namespace=”System.Configuration” %>
<script runat=”server”>
protected void Page_Load(object sender, EventArgs e)
{
SqlConnection DBCon;
SqlCommand OrdersCommand = new SqlCommand();
SqlCommand CustCommand = new SqlCommand();
SqlDataReader OrdersReader;
SqlDataReader CustReader;
IAsyncResult OrdersASyncResult;
IAsyncResult CustAsyncResult;
System.Threading.WaitHandle[] WHandles = new
System.Threading.WaitHandle[1];
System.Threading.WaitHandle OrdersWHandle;
System.Threading.WaitHandle CustWHandle;
DBCon = new SqlConnection();
DBCon.ConnectionString =
ConfigurationManager.ConnectionStrings[“DSN_NorthWind”].ConnectionString;
CustCommand.CommandText =
“ SELECT * FROM Customers WHERE CompanyName = ‘Alfreds Futterkiste’ “;
CustCommand.CommandType = CommandType.Text;
CustCommand.Connection = DBCon;
// Selecting all orders for a specific customer
“ Orders.OrderID, Orders.OrderDate, “ +
“ Orders.RequiredDate, Orders.ShippedDate “ +
“ FROM Orders, Customers “ +
“ WHERE Orders.CustomerID = Customers.CustomerID “ +
“ AND Customers.CompanyName = ‘Alfreds Futterkiste’ “ +
“ ORDER BY Customers.CompanyName, Customers.ContactName “;
OrdersCommand.CommandType = CommandType.Text;
OrdersCommand.Connection = DBCon;
DBCon.Open();
// Retrieving customer information asynchronously
CustAsyncResult = CustCommand.BeginExecuteReader();
// Retrieving orders list asynchronously
OrdersASyncResult = OrdersCommand.BeginExecuteReader();
CustWHandle = CustAsyncResult.AsyncWaitHandle;
OrdersWHandle = OrdersASyncResult.AsyncWaitHandle;
// Filling Wait Handles array with the two wait handles we
// are going to use in this code
WHandles[0] = CustWHandle;
WHandles[1] = OrdersWHandle;
System.Threading.WaitHandle.WaitAll(WHandles);
CustReader = CustCommand.EndExecuteReader(CustAsyncResult);
OrdersReader = OrdersCommand.EndExecuteReader(OrdersASyncResult);
gvCustomers.DataSource = CustReader;
gvCustomers.DataBind();
gvOrders.DataSource = OrdersReader;
gvOrders.DataBind();
DBCon.Close();
}
</script>
上面的代码显示了wait方法的优雅,然而在ADO.NET2.0中这不是最有效的代码。代码允许你可以在把结果集绑到到各自的GridView控件之前等待两个异步过程的调用结束。你可以修改代码如下所示以获取更好的效率。用WaitAny方法来代替WaitAll。WaitAny方法可以尽快处理一个调用结束的异步过程而不用等待其他过程结束。使用WaitAny方法你依然可以添加循环来保证其他过程调用结束后得到处理。WaitAny方法返回一个整数表示在WaitHanle数组中调用结束的那个异步过程的索引。使用这个返回值你可以得到wait句柄来处理一个已经结束的异步过程所返回的结果。
<%@ Page Language=”C#” %>
<%@ Import Namespace=”System.Data” %>
<%@ Import Namespace=”System.Data.SqlClient” %>
<%@ Import Namespace=”System.Configuration” %>
<script runat=”server”>
protected void Page_Load(object sender, EventArgs e)
{
SqlConnection DBCon;
SqlCommand OrdersCommand = new SqlCommand();
SqlCommand CustCommand = new SqlCommand();
SqlDataReader OrdersReader;
SqlDataReader CustReader;
IAsyncResult OrdersASyncResult;
IAsyncResult CustAsyncResult;
int WHIndex;
System.Threading.WaitHandle[] WHandles =
new System.Threading.WaitHandle[1];
System.Threading.WaitHandle OrdersWHandle;
System.Threading.WaitHandle CustWHandle;
DBCon = new SqlConnection();
DBCon.ConnectionString =
ConfigurationManager.ConnectionStrings[“DSN_NorthWind”].ConnectionString;
CustCommand.CommandText =
“ SELECT * FROM Customers WHERE CompanyName = ‘Alfreds Futterkiste’ “;
CustCommand.CommandType = CommandType.Text;
CustCommand.Connection = DBCon;
OrdersCommand.CommandText =
“ SELECT Customers.CompanyName, Customers.ContactName, “ +
“ Orders.OrderID, Orders.OrderDate, “ +
“ Orders.RequiredDate, Orders.ShippedDate “ +
“ FROM Orders, Customers “ +
“ WHERE Orders.CustomerID = Customers.CustomerID “ +
“ AND Customers.CompanyName = ‘Alfreds Futterkiste’ “ +
“ ORDER BY Customers.CompanyName, Customers.ContactName “;
OrdersCommand.CommandType = CommandType.Text;
OrdersCommand.Connection = DBCon;
// Opening the database connection
// Retrieving customer information asynchronously
CustAsyncResult = CustCommand.BeginExecuteReader();
// Retrieving orders list asynchronously
OrdersASyncResult = OrdersCommand.BeginExecuteReader();
CustWHandle = CustAsyncResult.AsyncWaitHandle;
OrdersWHandle = OrdersASyncResult.AsyncWaitHandle;
// Filling Wait Handles array with the two wait handles we
// are going to use in this code
WHandles[0] = CustWHandle;
WHandles[1] = OrdersWHandle;
// Looping 2 times because there are 2 wait handles
// in the array
for (int Index = 0; Index < 2; Index++ )
{
// We are only waiting for any of the two
// asynchronous process to finish running
WHIndex = System.Threading.WaitHandle.WaitAny(WHandles);
// The return value from the WaitAny method is
// the array index of the Wait Handle that just
// finsihed running
switch (WHIndex)
{
case 0:
CustReader = CustCommand.EndExecuteReader(CustAsyncResult);
gvCustomers.DataSource = CustReader;
gvCustomers.DataBind();
break;
case 1:
OrdersReader =
OrdersCommand.EndExecuteReader(OrdersASyncResult);
gvOrders.DataSource = OrdersReader;
gvOrders.DataBind();
break;
}
}
// Closing connection
DBCon.Close();
}
</script>