【问题标题】:What can I do to make this foreach loop run faster as it takes long time to execute?我该怎么做才能使这个 foreach 循环运行得更快,因为它需要很长时间才能执行?
【发布时间】:2019-12-14 19:00:47
【问题描述】:

我该怎么做才能使这个循环运行得更快?

    private void accessVendorGridData()
    {
        try
        {
            foreach (var item in getAllVendorList)
            {
                item.CurrencyName = "USD";

                // Fetch Addresses in Vendor Grid
                var Addr = _vendorservice.GetAllVendorAdd().Where(x => x.vendorId == item.Id).ToList();
                if (Addr.Count > 0)
                {
                    item.VendorAddressLine = String.Format("{0}, {1}, {2}, {3}, {4}", Addr[0].Address, Addr[0].City, Addr[0].StateProvince, Addr[0].ZipPostalCode, Addr[0].CountryRegion);
                }

                // Fetch Payment terms in Vendor Grid
                var paymentTerm = _vendorservice.GetAllPaymentTerms().Where(x => x.Id == item.PaymentTermId).ToList().SingleOrDefault();
                if (paymentTerm != null)
                {
                    item.paymenttermitem = paymentTerm.Name;
                }

                // Fetch Tax Scheme in Vendor Grid
                var taxscheme = _vendorservice.GetAllTaxScheme().Where(x => x.Id == item.TaxschemeId).ToList().SingleOrDefault();
                if (taxscheme != null)
                {
                    item.TaxschemeName = taxscheme.TaxSchemaName;
                }
            }
        }
        catch (Exception ex)
        {
            _exLog.AddErrorLog(ex, "NewVendor, accessVendorGridData()");
            ModernDialog.ShowMessage(ex.Message, "Error!", MessageBoxButton.OK);
        }
    }

我能做些什么来让这个循环运行得更快?我尝试了 Parallel.ForEach 但在两者之间迷路了。有人可以帮忙吗?

private void accessVendorGridData()
    {
            foreach (var item in getAllVendorList)
            {
                var Addr = _vendorservice.GetAllVendorAdd().Where(x => x.vendorId == item.Id).ToList();
                var paymentTerm = _vendorservice.GetAllPaymentTerms().Where(x => x.Id == item.PaymentTermId).ToList().SingleOrDefault();
                var taxscheme = _vendorservice.GetAllTaxScheme().Where(x => x.Id == item.TaxschemeId).ToList().SingleOrDefault();
            }
    }

【问题讨论】:

  • 首先要做的是:测量该循环是否真的是一个瓶颈,或者如果你只是感觉到它很慢,因为通过调试器单步执行每一行需要一些时间。除此之外,我们无法回答这个问题,因为我们不知道循环中的方法是做什么的,以及这些方法是否会导致性能不佳。长篇大论:使用分析器,例如点追踪。
  • 从删除 materialization 开始:.ToList() 但改用Any()
  • 为了得到准确的答案,我们还需要知道vendorservice内部做了什么
  • .ToList().SingleOrDefault() 变成.SingleOrDefault() 不需要在ToList() 当你想要单品时
  • 您似乎在每次迭代时都在调用 GetAllVendorAddGetAllPaymentTermsGetAllTaxScheme 。您可以考虑从循环中提取此通用代码并将其结果具体化为列表或数组。

标签: c# multithreading performance for-loop foreach


【解决方案1】:

您可以从循环中提取vendorspaymentTermsallTaxSchemes 作为字典,而不是在每次迭代中查询

private void accessVendorGridData() {
  var vendors = _vendorservice
    .GetAllVendorAdd()  
    .GroupBy(item => item.Id)
    .ToDictionary(chunk => chunk.Key, chunk => chunk.ToList());

  var paymentTerms = _vendorservice
    .GetAllPaymentTerms()
    .GroupBy(item => item.Id)
    .ToDictionary(chunk => chunk.Key, chunk => chunk.SingleOrDefault());

  var allTaxSchemes = _vendorservice
    .GetAllTaxScheme()
    .GroupBy(item => item.Id)
    .ToDictionary(chunk => chunk.Key, chunk => chunk.SingleOrDefault());

  foreach (var item in getAllVendorList) {
    var Addr = vendors.TryGetValue(item.Id, out var addrs) 
       ? addrs 
       : new List<Vendor>(); //TODO: put the right type instead of Vendor

    var paymentTerm = paymentTerms.TryGetValue(item.PaymentTermId, out var term) 
       ? term 
       : null;

    var taxscheme = allTaxSchemes.TryGetValue(item.PaymentTermId, out var scheme) 
       ? scheme 
       : null;
  } 
}

您当前的代码有

O(|getAllVendorList| * (|vendors| + |paymentTerms| + |allTaxSchemes|))

时间复杂度,这个有

O(|getAllVendorList| + |vendors| + |paymentTerms| + |allTaxSchemes|)

但是,如果_vendorservice.GetXXX() 是对服务、RDBMS 等的查询,并且您必须在每次迭代时调用它(因为可以更改数据),这不是解决方案

【讨论】:

  • 感谢@DmirtyBychenko 的代码...几乎一切正常,但 var Addr = vendor.TryGetValue(item.Id, out var addrs) 部分?地址:新列表();没有输出。
  • @Abhishek Thakur:如果我们有供应商列表 vendors.TryGetValue(item.Id, out var addrs) ?,我们会返回它 - ? addr,如果没有(未知 item.Id),我们会返回一个空列表 - : new List&lt;Vendor&gt;();。请输入正确的类型而不是Vendor
猜你喜欢
  • 2013-10-21
  • 1970-01-01
  • 2021-02-17
  • 1970-01-01
  • 2012-12-03
  • 2011-03-14
  • 2021-01-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多