代码之家  ›  专栏  ›  技术社区  ›  Ogglas

中的并发请求ASP.NETwebapi2的速度几乎是单个请求的六倍

  •  0
  • Ogglas  · 技术社区  · 6 年前

    背景:

    我们建了一个React SPA,可以与ASP.NETWeb API 2后端。 NET Framework 4.6.1 . 在初始加载时,我们会发出两个单独的请求来加载数据。在加载大量数据时,我们注意到,当我们在应用程序中发出API请求时,它们都比在Postman中单独尝试请求时慢得多。

    原件:

    示例结构,fetch当然使用我们的API:

    fetch('http://example.com/movies.json')
      .then(function(response) {
        return response.json();
      })
      .then(function(myJson) {
        console.log(JSON.stringify(myJson));
      });
    
    fetch('http://example.com/otherMovies.json')
      .then(function(response) {
        return response.json();
      })
      .then(function(myJson) {
        console.log(JSON.stringify(myJson));
      });
    

    示例C#API方法:

    [HttpGet]
    [Route("{bsid}/{caseId}")]
    public IHttpActionResult GetRenewalCycleForCustomer(string bsid, int caseId)
    {
        var customerNumbers = GetCustomerNumbers();
    
        var userId = HttpContext.Current.User.Identity.GetUserId<int>();
    
        var user = identityDb.Users.Find(userId);
    
        var customerNumbers = user.ApplicationUserCustomerNumbers.Select(x => new CustomerNumberKey() { bsid = x.CustomerNumber.bsid, NameNo = x.CustomerNumber.NameNo }).ToList();
    
        var db = new DbContext();
    
        var caseService = new CaseService(db);
    
        var portfolioTabViewModel = caseService.GetPortfolioTabViewModelForCustomer(bsid, caseId, customerNumbers);
    
        return Ok(portfolioTabViewModel);
    }
    

    enter image description here

    两个邮递员同时走的例子:

    enter image description here

    其他注意事项:

    我们能做些什么来解决这个问题?

    似乎并行运行的非异步方法:

    https://stackoverflow.com/a/26737847/3850405

    Web.config 这不是我所能做到的。搜索 HttpContext.Current.SetSessionStateBehavior 给出0个结果。

    https://stackoverflow.com/a/26172317/3850405

    https://serverfault.com/a/800518/293367

    https://forums.asp.net/t/2100558.aspx?concurrent+connections+on+windows+pro+10+IIS

    更新异步和IIS:

    它似乎与async或IIS无关,IIS使用下面的方法测试并发请求。并发的慢请求似乎依赖于其他东西。

    异步:

    [HttpGet]
    [Route("{bsid}/{caseId}")]
    public async Task<IHttpActionResult> Get(string bsid, int caseId)
    {
        await Task.Delay(3000);
        return Ok();
    }
    

    enter image description here

    同步:

    [HttpGet]
    [Route("{bsid}/{caseId}")]
    public IHttpActionResult Get(string bsid, int caseId)
    {
        Thread.Sleep(3000);
        return Ok();
    }
    

    enter image description here

    它似乎也不是数据库调用。测试 Include 尽管异步调用的速度要慢得多,但调用的速度是相似的。

    [HttpGet]
    [Route("{bsid}/{caseId}/async")]
    public async Task<IHttpActionResult> GetAsync(string bsid, int caseId)
    {
        var db = new DbContext();
    
        var deviations = await db.RenewalCycles.Where(x => x.Deviations.Any())
            .Include(cycle => cycle.TPCase.CaseNames.Select(caseName => caseName.TPName))
            .Include(cycle => cycle.TPCase.CaseNames.Select(caseName => caseName.TPNameType))
            .Include(cycle => cycle.TPCase.GoodsAndServicesDescriptions)
            .Include(cycle => cycle.TPCase.RelatedCases.Select(relatedCase => relatedCase.TPCaseRelation))
            .Include(cycle => cycle.TPCase.RelatedCases.Select(relatedCase => relatedCase.TPCountry))
            .ToListAsync();
    
        return Ok();
    }
    

    enter image description here

    同步:

    [HttpGet]
    [Route("{bsid}/{caseId}")]
    public IHttpActionResult Get(string bsid, int caseId)
    {
        var db = new DbContext();
    
       var deviations = db.RenewalCycles.Where(x => x.Deviations.Any())
            .Include(cycle => cycle.TPCase.CaseNames.Select(caseName => caseName.TPName))
            .Include(cycle => cycle.TPCase.CaseNames.Select(caseName => caseName.TPNameType))
            .Include(cycle => cycle.TPCase.GoodsAndServicesDescriptions)
            .Include(cycle => cycle.TPCase.RelatedCases.Select(relatedCase => relatedCase.TPCaseRelation))
            .Include(cycle => cycle.TPCase.RelatedCases.Select(relatedCase => relatedCase.TPCountry))
            .ToList();
    
        return Ok();
    }
    

    enter image description here

    1 回复  |  直到 6 年前
        1
  •  0
  •   Ogglas    6 年前

    最终证明,开销部分与数据库相关。使用的方法 db.Cases.Find(bsid, caseId) Cases 模型反过来又有很多关系,所有这些关系都发出一个单独的数据库调用,因为模型的属性被标记为 virtual public virtual TPRenewalCycle TPRenewalCycle { get; set; } 启用延迟加载。通过查看visualstudio输出窗口(Debug->Windows->Output)并设置如下ApplicationDbContext找到它。

    public class ApplicationDbContext : DbContext
    {
        protected const string ConnectionStringName = "defaultConnection";
        public ApplicationDbContext() : base(ConnectionStringName)
        {
            Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
            Database.CommandTimeout = 300;
        }