当前位置: 首页 > 知识库问答 >
问题:

异步和等待:它们不好吗?

锺离鸿
2023-03-14

该站点由一个托管在4节点集群上的API(WEB API)站点和一个托管在另一个4节点集群上并调用该API的WEB站点组成。两者都是使用ASP.NET MVC5开发的,所有操作/方法都基于async-await方法。

在一些监视工具(如NewRelic)下运行站点、调查几个转储文件并分析工作进程之后,结果发现,在负载非常轻的情况下(例如16个并发用户),我们最终拥有大约900个线程,使用了100%的CPU并填满了IIS线程队列!

尽管我们通过引入大量缓存和性能修正将站点部署到了生产环境中,但我们团队中的许多开发人员认为,我们必须删除所有异步方法,并将API和web站点都隐藏到普通的web API和操作方法中,这些方法只返回操作结果。

public static async Task<T> GetApiResponse<T>(object parameters, string action, CancellationToken ctk)
{
        using (var httpClient = new HttpClient())
        {
            httpClient.BaseAddress = new Uri(BaseApiAddress);

            var formatter = new JsonMediaTypeFormatter();

            return
                await
                    httpClient.PostAsJsonAsync(action, parameters, ctk)
                        .ContinueWith(x => x.Result.Content.ReadAsAsync<T>(new[] { formatter }).Result, ctk);
        }
    }
public async static Task<IList<DownloadType>> GetSupportedContentTypes()
{
  string userAgent = Request.UserAgent;
  var parameters = new { Util.AppKey, Util.StoreId, QueryParameters = new { UserAgent = userAgent } };
  var taskResponse = await  Util.GetApiResponse<ApiResponse<SearchResponse<ProductItem>>>(
                    parameters,
                    "api/Content/ContentTypeSummary",
                    default(CancellationToken));
                    return task.Data.Groups.Select(x => x.DownloadType()).ToList();
 }
public async Task<ActionResult> DownloadTypes()
    {
        IList<DownloadType> supportedTypes = await ContentService.GetSupportedContentTypes();

共有1个答案

林弘壮
2023-03-14

这种方法有什么傻吗?注意,当我们将所有方法转换为非异步方法时,我们得到了更好的性能堆。

我可以看到这里至少有两件事出错了:

public static async Task<T> GetApiResponse<T>(object parameters, string action, CancellationToken ctk)
{
        using (var httpClient = new HttpClient())
        {
            httpClient.BaseAddress = new Uri(BaseApiAddress);

            var formatter = new JsonMediaTypeFormatter();

            return
                await
                    httpClient.PostAsJsonAsync(action, parameters, ctk)
                        .ContinueWith(x => x.Result.Content
                            .ReadAsAsync<T>(new[] { formatter }).Result, ctk);
        }
    }

首先,传递给ContinueWith的lambda正在阻塞:

x => x.Result.Content.ReadAsAsync<T>(new[] { formatter }).Result
x => { 
    var task = x.Result.Content.ReadAsAsync<T>(new[] { formatter });
    task.Wait();
    return task.Result;
};
return
    await
        httpClient.PostAsJsonAsync(action, parameters, ctk).ContinueWith(
            x => x.Result.Content.ReadAsAsync<T>(new[] { formatter }), 
            ctk,
            TaskContinuationOptions.None, 
            TaskScheduler.FromCurrentSynchronizationContext()).Unwrap();
var x = await httpClient.PostAsJsonAsync(action, parameters, ctk);
return await x.Content.ReadAsAsync<T>(new[] { formatter });

如果我必须在同步上下文中调用一个异步方法,在这个上下文中不可能使用await,最好的方法是什么?

您几乎不需要将awaitcontinution混合使用。对于,您应该坚持使用await。基本上,如果使用async,它必须“全程”异步。

对于服务器端ASP.NET MVC/Web API执行环境,这只是意味着控制器方法应该是异步并返回任务任务<>,请检查此选项。ASP.NET跟踪给定HTTP请求的挂起任务。只有完成所有任务后,请求才会完成。

对于客户端UI应用程序,可以从同步方法调用异步方法。例如,您可以使用ContinueWith(action,taskScheduler.FromCurrentSynchronizationContext())并从action激发一个完成事件(如下所示)。

 类似资料:
  • 我一直试图理解C#中的Async/await和Task,但尽管看了youtube视频,阅读了文档,并参加了pluralsight课程,但一直失败得很厉害。 我希望有人能帮助回答这些稍微抽象的问题,帮助我的大脑摆脱困境。 1.为什么说async/await启用了一个“Asynchonrous”方法,而async关键字本身什么也不做,而await关键字添加了一个挂起点?添加挂起点不是强制方法同步操作,

  • 我正在尝试将数据库调用移出控制器,以清理并使其可测试。当它们在控制器中时,一切都会顺利进行。我将它们移出控制器,并添加了一个异步,以确保我们等待。否则,我将调用的中的函数。现在,一旦我使用async/await,控制器中的函数就会认为没有用户,因为它没有等待。 有几个关于异步等待的SO问题,但我没有找到一个解决我的问题。我确实验证了返回了我的用户,并添加了控制台日志来显示路径。 节点猫鼬异步等待似

  • 我试图在react/electron项目中使用async/await,但它不起作用。我想要的是获取docker容器状态列表。但是安慰。日志(列表)返回未定义的。 有人能帮我吗?:)

  • 在实际应用中,我对 C# 中的异步和 await 方法进行了说明。请考虑以程,这是工作代码的简单版本: 助手.cs 功能控制器.cs processing.js 现在,问题是第三方服务的所需时间更少(例如:2秒),而所需的时间更多(例如:100秒)。进行两个ajax调用并使用异步和等待是为了呈现自我。屏幕上显示数据1,不要等到自己。Data2已被检索。不幸的是,这种情况没有发生,我必须等待100秒

  • 我正试图将图像上传到firebase存储,但调用该函数时,未执行wait以获取url。我错过了什么? 看看这个其他主题,我发现问题可能是“然后”,但我如何设置代码以等待url? 异步/等待/然后飞镖/颤振 谢谢

  • 我用webpack建立了一个浏览器umd库。 我正在侦听输入文件的onchange事件。当有人提交图像/文件时,它会将其转换为base64。我试图让它尽可能看起来不那么明显,所以我使用了promises和wait/asynchttps://blog.shovonhasan.com/using-promises-with-filereader/. 但是,有一个问题-当我调用convertToBase