我正在使所有数据库操作异步。但是,我似乎没有得到异步的预期结果。
例如-
我正在循环中向数据库中的表中插入 100 行。执行此操作的函数是异步函数。在等待时,它似乎不会将控制权交给调用者。代码如下 -
[HttpGet]
[Route("/api/logtest")]
public async Task<JObject> logTestAsync()
{
JObject retval = new JObject();
DateTime dt1 = DateTime.Now;
Task t = BulkLogInsertAsync();
DateTime dt2 = DateTime.Now;
retval["Exec_Time"] = dt2.Subtract(dt1).TotalMilliseconds;
await t;
DateTime dt3 = DateTime.Now;
retval["Await_Time"] = dt3.Subtract(dt2).TotalMilliseconds;
return retval;
}
private async Task BulkLogInsertAsync()
{
List<Task<int>> allTasks = new List<Task<int>>();
for (int i = 0; i<100;i++)
{
allTasks.Add(LogInsertAsync("insert into logs values (getdate() , 'custom' , 'sample message. ', 'Log.bills', 'callsite1', '', '', '')"));
//allTasks.Add(LogInsertAsync("WAITFOR DELAY '00:00:02';"));
}
await Task.WhenAll(allTasks.ToArray()).ConfigureAwait(false);
}
private async Task<int> LogInsertAsync(string cmd)
{
int res = 0;
using (SqlConnection hookup = new SqlConnection(@"[mycnstr]"))
{
Task connectionOpeningTask = hookup.OpenAsync();
using (SqlCommand sqlcmd = new SqlCommand(cmd, hookup))
{
await connectionOpeningTask.ConfigureAwait(false);
res = await sqlcmd.ExecuteNonQueryAsync().ConfigureAwait(false);
}
hookup.Close();
}
return res;
}
当我第一次调用 API /api/logtest 时,我似乎得到了所需的结果,其中 exec_time 比 wait_time 少得多(0.2 秒 vs 4 秒)
但是从第二次运行开始,我得到的await_time比exec_time少得多(4s vs 0.2s),这让我相信代码是同步运行的。
使用 .net Framework 4.6.1 的控制台应用程序中的相同代码也可以连续给出所需的结果。不,我没有重新启动控制台应用程序。在 do while 循环中运行 BulkLogInsertAsync :-)
有人可以告诉我哪里出错了吗?
让我们澄清一些事情:
好吧,首先,你的应用程序以预定义数量的等待线程启动(通常是核心数*2,如果我没记错的话,我找不到那篇该死的 MSDN 文章)。如果你请求线程并且你在这个限制下使用,你会立即获得它们,否则,你将不得不等待 500 毫秒(找不到文章)
第二,异步不是并行!
第三,在你的代码中,只要你使用await,它就会等待!所以,我建议你重构
OpenAsync
上的等待,与 ContinueWith
链接,并且只在代码中使用一次等待,因为,就像现在一样,你的 using
正在阻止 async
正常工作。 ..如果您希望代码异步运行,您将必须自己管理连接和处置
编辑1:
线程有两种类型:IO线程和工作线程。在你的代码中,你需要的是数据库的 IO 线程到 w8...如果你需要更多上下文,你可以从这里开始