在 ASP.NET Web API 中从异步方法调用同步方法

问题描述 投票:0回答:1

我正在开发一个 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));
        }       
    }
}

会造成死锁吗?

c# asp.net asp.net-web-api async-await
1个回答
3
投票

您不应该使用

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
),直到您准备好使数据库方法异步。
    

© www.soinside.com 2019 - 2024. All rights reserved.