异步操作 (ADO.NET)
某些数据库操作(例如命令执行)可能要花费很长时间才能完成。 在此类情况下,单线程应用程序必须阻塞其他操作,并且等待该命令完成,然后才可以继续执行它们自己的操作。 比较而言,如果能够将长时间运行的操作分配给某个后台线程,就可以允许前台线程在整个操作期间保持活动状态。 例如,在 Windows 应用程序中,通过将长时间运行的操作委托给后台线程,可允许用户界面线程在操作执行时保持响应状态。
.NET Framework 提供若干标准异步设计模式,开发人员可以通过这些模式充分利用后台线程并释放用户界面线程或高优先级的线程以完成其他操作。 ADO.NET 在其 SqlCommand 类中支持相同的设计模式。 具体而言,BeginExecuteNonQuery、BeginExecuteReader 和 BeginExecuteXmlReader 方法(与 EndExecuteNonQuery、EndExecuteReader 和 EndExecuteXmlReader 方法搭配)提供异步支持。
只在 Microsoft Windows XP 和 Windows 2000 中支持这些方法,在 Windows 98 或 Windows ME 中不支持这些方法。
说明: |
异步编程是 .NET Framework 的核心功能,并且 ADO.NET 充分利用了标准设计模式。 有关可供开发人员使用的不同异步技术的更多信息,请参见使用异步方式调用同步方法。 |
尽管将异步技术与 ADO.NET 功能一起使用没有什么新增的需特别注意的事项,但与 .NET Framework 的其他领域相比,很可能更多的开发人员将在 ADO.NET 中使用异步功能。 了解创建多线程应用程序的优缺点十分重要。 本节之后的那些示例指出了若干重要问题,开发人员在开发纳入了多线程功能的应用程序时将需要考虑这些问题。
本节内容
提供一个示例,演示如何安全地执行异步命令,并且通过单独线程正确处理与某一窗体及其内容的交互。
使用等待句柄的 ASP.NET 应用程序 (ADO.NET)
提供一个示例,演示如何从 ASP.NET 页执行多个并行命令,并且使用等待处理管理在所有命令都完成时的操作。
提供一个示例,演示如何在控制台应用程序中使用轮询来等待异步命令执行的完成。 在类库或没有用户界面的其他应用程序中此技术同样有效。
上述说明来自Mircrosoft TeachNet http://technet.microsoft.com/zh-cn/zw97wx20.aspx。在以往开发过程中,还未考虑到对数据库的优化,以至于埋没了ADO.NET Asynchronously功能。在使用过程中我总结:同步和异步连接数据库各有利弊,同步在连接数据库时,数据在下载过程中IE甚至机器较慢。在数据库的下载过程中,IE是等数据完全下载完以后才呈现给用户,用户才可以操作控制,这时IE所呈现给我们的只是一个全白界面,让人等起来心急;相反,异步连接数据库下载数据同时,可以对机器进行操作。这里所指的操作最好只限查询操作,因为连接句柄正在使用,进行Insert、Update等操作时可能会引发异常。所以在使用时一定要适当。下面将附上异步显示数据库与普通连接数据库的代码,同时利用HttpWatch进行查看。
private static string connectionString = @"Data Source=CHINESE-3F6F8FF"SQLEXPRESS;
Initial Catalog=Northwind;User ID=sa;Pwd=000000;Asynchronous Processing=true;";
private const string sqlSelectString = "Select * from products ";
private DateTime startTime, endTime;
protected void Page_Load(object sender, EventArgs e)
{
//非异步连接数据库
startTime = DateTime.Now;
SqlConnection conn = new SqlConnection(connectionString);
SqlCommand cmd = conn.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = sqlSelectString;
conn.Open();
long startTicks = DateTime.Now.Ticks;
SqlDataReader result = cmd.ExecuteReader();
GridView1.DataSource = result;
GridView1.DataBind();
long endTicks = DateTime.Now.Ticks;
Label1.Text = ("Time taken : " + (endTicks - startTicks) + " ticks.");
;
conn.Close();
//异步操连接数据库并查询
//if (!IsPostBack)
//{
// BindData();
// Label2.Text = (endTime - startTime).ToString();
//}
}
private void Page_Unload(object sender, System.EventArgs e)
{
endTime = DateTime.Now;
}
private void BindData()
{
using (SqlConnection conn = new SqlConnection(connectionString))
{
SqlCommand cmd = new SqlCommand(sqlSelectString, conn);
IAsyncResult ASynResult;
SqlDataReader dr;
try
{
conn.Open();
//begin方法返回一个IAsyncResult对象,用来检查执行是否完成
ASynResult = cmd.BeginExecuteReader(CommandBehavior.CloseConnection);
while (!ASynResult.IsCompleted)
{
ASynResult.AsyncWaitHandle.WaitOne(3000, true);
}
dr = cmd.EndExecuteReader(ASynResult);
GridView1.DataSource = dr;
GridView1.DataBind();
}
catch (Exception ex)
{
Response.Write(ex.Message);
}
}
}
在页面上我利用页面的加载与卸载来计算页面用时,但有很多不确定的因素,无法计算出两种情况哪个更节省时间,见下图:

