以下是我正在使用的代码。旨在使其成为对耗时功能的异步调用。
async Task<DataSet> GetDataAsync()
{
System.Threading.Thread.Sleep(5000);
SqlDataAdapter adpator = new SqlDataAdapter("Select * from table1;select * from table2;select * from table3;select * from table4"
, @"Data Source=ANKIT\SQLEXPRESS;Initial Catalog=IM_DB;Integrated Security=True");
DataSet ds = new DataSet();
adpator.Fill(ds);
return ds;
}
protected async void btnFillData_Click(object sender, EventArgs e)
{
lblStatus.Text = "Going to run a blocking thread....";
Task<DataSet> dsAsync = GetDataAsync();
lblStatus.Text = "Going to await the same......";
DataSet ds = await dsAsync;
lblStatus.Text = "released from await";
gvIngredient.DataSource = ds.Tables[0];
gvIngredient.DataBind();
}
功能 GetDataAsync 作为同步调用。我希望它是异步的,因为它正在进行数据库调用以获取数千条记录,这非常耗时。
我在asp.net的异步模型中遗漏了一些东西。
答案 0 :(得分:2)
第一个问题:
修饰符async
不会使您的方法异步,它只是让您有机会在里面使用await
关键字。因此,函数GetDataAsync
不是异步的 - 它使用与调用它相同的线程。要使此函数异步,您必须使用Task
类和StartNew
方法,如下所示:
Task<DataSet> GetDataAsync()
{
Function<DataSet> func = () =>
{
System.Threading.Thread.Sleep(5000);
SqlDataAdapter adpator = new SqlDataAdapter("Select * from table1;select * from table2;select * from table3;select * from table4"
, @"Data Source=ANKIT\SQLEXPRESS;Initial Catalog=IM_DB;Integrated Security=True");
DataSet ds = new DataSet();
adpator.Fill(ds);
return ds;
};
return Task.Factory.StartNew(func);
}
检查this非常有用的文章,了解async\await
的工作原理。
第二个:
每次调用SqlDataAdapter
后,您的代码会将GetDataAsync
保留在内存中。此行为导致内存泄漏。您最好使用using
声明:
DataSet ds = new DataSet();
using(var adapter = new SqlDataAdapter(query, connectionString))
adapter.Fill(ds);
希望这有帮助。
答案 1 :(得分:0)
功能GetDataAsync作为同步调用。
是。事实上,有一个编译器警告会告诉你GetDataAsync
将同步运行。
可以使其异步,但不能使用DataSet.Fill
方法。这是一种很老的做事方式,并没有更新为使用新的异步API。您必须使用类似Entity Framework 6或异步DbCommands的东西。
但是在你走这条路之前......
protected async void btnFillData_Click(object sender, EventArgs e)
{
lblStatus.Text = "Going to run a blocking thread....";
Task<DataSet> dsAsync = GetDataAsync();
lblStatus.Text = "Going to await the same......";
DataSet ds = await dsAsync;
lblStatus.Text = "released from await";
gvIngredient.DataSource = ds.Tables[0];
gvIngredient.DataBind();
}
此代码显示了对ASP.NET如何工作的误解。单击该按钮时,会向ASP.NET服务器发送一个HTTP请求,并且服务器只能发送一个HTTP响应。此响应仅在click事件方法的 end 处发送。因此,多次设置lblStatus.Text
不会产生任何影响 - 用户只能看到最后一次更新。
换句话说,ASP.NET上的await
只会产生ASP.NET运行时;它不会屈服于客户端(浏览器)。在所有await
完成之前,不会发送HTTP响应。
那么,你真正询问的是如何启动在ASP.NET中长时间运行的操作,然后让客户端稍后更新 有进度或完成信息。为此,您需要一种不同的技术,例如SignalR,AJAX或UpdatePanel
。