c# - 异步更新多行立即更新1/4的行然后等待
问题描述
我有一个代码可以异步更新 SQL Server 表中的多行。我在更新 540 行时对其进行了测试,并在表中即时更新了 144 行,然后等待大约 5 分钟,然后更新其余的行。至少这是当我使用 SELECT 检查更新的行时的样子。我想知道为什么会这样。
整个事情是由按钮的点击触发的:
DialogResult res = MessageBox.Show($"Znaleziono {num} pasujących maszyn. Czy chcesz zaktualizować priorytet maszyny danymi z pliku?", "Potwierdź", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if(res == DialogResult.Yes)
{
await UpdatePriority();
MessageBox.Show("Updated!");
这是 UpdatePriority 方法,它为项目列表中的所有位置异步调用 place.Edit() 方法:
public async Task<string> UpdatePriority()
{
List<Task<string>> UpdateTasks = new List<Task<string>>();
try
{
foreach (Place p in Items.Where(i => i.IsUpdated==true))
{
UpdateTasks.Add(Task.Run(()=> p.Edit()));
}
string response = "OK";
IEnumerable<string> res = await Task.WhenAll<string>(UpdateTasks);
}
catch (Exception ex)
{
throw;
}
return "Nie udało się zaktualizować danych żadnego zasobu..";
}
这是地方对象的 Edit() 方法。它基本上更新了 SQL Server 表中的位置数据:
public async Task<string> Edit()
{
string iSql = @"UPDATE JDE_Places
SET Priority=@Priority
WHERE PlaceId=@PlaceId";
string msg = "OK";
using (SqlCommand command = new SqlCommand(iSql, Settings.conn))
{
command.Parameters.AddWithValue("@PlaceId", PlaceId);
command.Parameters.AddWithValue("@Priority", Priority);
int result = -1;
try
{
result = await command.ExecuteNonQueryAsync();
IsUpdated = false;
}
catch (Exception ex)
{
msg = $"Wystąpił błąd przy edycji zasobu {Name}. Opis błędu: {ex.Message}";
}
}
return msg;
}
这是用作可重用连接对象的 Settings conn 属性:
public static class Settings
{
private static SqlConnection _conn { get; set; }
public static SqlConnection conn
{
get
{
if (_conn == null)
{
_conn = new SqlConnection(Static.Secrets.ConnectionString);
}
if (_conn.State == System.Data.ConnectionState.Closed || _conn.State == System.Data.ConnectionState.Closed)
{
try
{
_conn.Open();
}
catch (Exception ex)
{
MessageBox.Show("Nie udało się nawiązać połączenia z bazą danych.. " + ex.Message);
}
}
return _conn;
}
}
}
我意识到将连接保持在 using 语句中可能会更好(而不是重用它),但是当我将它添加到 place.Edit() 方法时,它的工作速度甚至更慢(并且不可靠)。
更新:我又跑了几个测试,他们添加 540 行所花费的时间从 15 秒到 400 秒不等。然后我只是在地方对象的 Edit() 中更改result = await command.ExecuteNonQueryAsync()
,result = command.ExecuteNonQuery()
再跑了几个测试,全部在 10 秒内完成!不过,我不知道为什么 ExecuteNonQuery() 的异步版本比非异步版本差这么多。单个 Edit() 方法使用 ExecuteNonQuery() 大约需要 0.1 秒,使用 ExecuteNonQueryAsync() 大约需要 1 - 400 秒。以下是日志:ExecuteNonQuery() ExecuteNonQueryAsync()
解决方案
你的问题是你的Settings
班级。您实际上是在尝试SqlConnection
在多个Sqlcommand
s 中使用相同的对象。SqlConnection
像这样使用时不是线程安全的。你最终会得到多个命令,因为你的代码是非阻塞和异步的。这就是导致您的代码“等待”(或死锁)的原因。这就是为什么当您运行它时同步(没有ExecuteNonQueryAsync
等)它可以正常工作。
反正你根本不需要这个对象。ADO.Net 为您处理连接池,因此重用它没有任何优势SqlConnection
。只需为每个创建一个新的SqlCommand
:
public async Task<string> Edit()
{
using (SqlConnection conn = new SqlConnection(...))
using (SqlCommand command = new SqlCommand(iSql, conn))
{
...
}
}
你应该会发现你的“等待”消失了。
推荐阅读
- go - 在 go 中的包内共享变量
- java - java在服务器和客户端之间传输文件,传输未完成
- java - 编译 Confluent KsqlDB 时的类型转换问题
- windows - 重新启动 WinRM 服务
- javascript - 如何访问名为日期的对象参数
- scala - 基于 csv 映射向数据框添加新列(通用方法)
- javascript - 将对象数组加入新数组对象
- sql - 用于连接 3 个表的 SQL 视图,但有多个列可用于 ON 子句
- arrays - 如何在不使用类的情况下仅从数组中随机选择每种颜色一次
- c# - IApplicaionBuilder 不包含定义 MapSignalR()。app.MapSignalR() 在 ASP.NET CORE 上不起作用