我正在开发一个 ASP.NET Web API 项目。我是异步编程新手。
在我的
GetOrderNumberAsync
异步方法中,我必须调用遗留同步方法,如第 20 行所示。这是一个数据库调用,用于更新 SQL Server 表中的数据。
我正在考虑使用
Task.Run()
重写它,如下面第一行注释掉的行所示:
[HttpPost]
[Route("FreshOrder")]
public async Task FreshOrder([FromBody] JObject jsonResult)
{
string resourceURL = JObject.Parse(jsonResult.ToString())["resource_url"].ToString();
await GetOrderNumberAsync(resourceURL);
}
private async Task GetOrderNumberAsync(string queryURL)
{
int rowsAffected;
using (HttpClient client = new HttpClient())
{
string resp = await client.GetStringAsync(queryURL);
var jObj = JObject.Parse(resp);
JArray orders = (JArray)jObj["orders"];
foreach (JToken order in orders)
{
string customerId = (string)order["customerId"];
string customerNumber = (string)order["customerNumber"];
rowsAffected = order.UpdateData(customerId, customerNumber);
//rowsAffected = await Task.Run(() =>
// order.UpdateData(customerId,
//customerNumber));
}
}
}
会造成死锁吗?
您不应该使用
Task.Run
,但不是出于您认为的原因。
Task.Run
不会导致死锁。当单线程上下文中的异步代码上的某些代码阻塞时,就会发生“常见死锁”。在本例中,代码在后台线程 (Task.Run
) 上运行同步代码,然后对其进行 await
操作。这不会陷入僵局。但是,您仍然不应该使用Task.Run
。这是因为 ASP.NET
已经在线程池线程上运行此请求。
await Task.Run
将把部分请求(数据库更新)调度到不同线程池线程上,然后“屈服”回 ASP.NET 运行时,将当前线程池线程返回到线程池。因此,在 ASP.NET 上,
Task.Run
只会导致线程切换,而不会提供任何好处。 引用: 您可以通过等待 Task.Run 来启动一些后台工作,但这样做是没有意义的。事实上,这实际上会通过干扰 ASP.NET 线程池启发法来损害您的可伸缩性...作为一般规则,不要将工作排队到 ASP.NET 上的线程池。
已经如果该方法是异步的
(或者如果该方法有异步版本),那么您的代码当然应该将其与await
一起使用。但由于代码是同步的,因此只需将其设为直接同步调用(否
Task.Run
),直到您准备好使数据库方法异步。