处理foreach循环的执行时间过长

时间:2015-10-07 00:00:28

标签: c# foreach umbraco-ucommerce

我正在处理一些更新UCommerce中的项目的代码(不是我自己的代码)。这个特定的代码块更新了产品的UDF。我遇到了执行速度的问题。通过foreach循环的每次迭代都比前一次慢。执行开始时,它每秒循环5-6次,但是当它处理500次迭代时,它每5-6秒减速到1次,现在是910项,每10-11秒减速到1次。正如代码所示,它在提交事务和刷新会话之前处理200(_batchsize)项。

内存,CPU和磁盘IO看起来都很好。没有过多的CPU使用率,充足的可用内存和没有磁盘瓶颈。运行应用程序时,内存使用率保持稳定在350Mb左右。

无论是从IDE还是已编译的exe运行它,我都会看到同样的问题。

我已经尝试减少批量大小,我也尝试提交事务并刷新每个项目的会话但它没有什么区别。我只是想知道是否有人可以提出任何我可以尝试的建议,甚至可以确定可能的问题区域。

public class ccProductUDFs
{
    public string ProductName { get; set; }
    public string FieldName { get; set; }
    public string DataType { get; set; }
    public string DisplayName { get; set; }
    public string SKU { get; set; }
    public bool Facet { get; set; }
    public bool Searchable { get; set; }
    public bool RenderInEditor { get; set; }
    public string DefinitionName { get; set; }
    public string DefinitionDescription { get; set; }
    public string UdfValue { get; set; }
    public bool UdfValueHasChanged { get; set; }
    public bool UdfFieldHasChanged { get; set; }
    public bool UdfFieldDeleted { get; set; }
    public bool DisplayOnSite { get; set; }
    public string CultureCode { get; set; }

    public override string ToString()
    {
        return string.Format("{0} {1} : {2} = {3}", this.SKU, this.ProductName, this.DisplayName, this.UdfValue);
    }
}

//This will load approx. 173000 item for a SQL database
 List<ccProductUDFs> listudfs = ccProductUDFsData.Load(DBConfiguration.GetDBContext());
//_batchsize is set to 200

//processUdFs  is a Boolean = true stored in AppSettings

    #region Update any UDFs...

    _startrange = 0;
    started = DateTime.Now;
    timeTaken = TimeSpan.MinValue;
    timeLeft = TimeSpan.MinValue;
    doneCount = 0;
    _totalCount = listudfs.Count();
    while (_processUdFs && _startrange < listudfs.Count())
    {
        int sz = listudfs.Count() - _startrange >= _batchsize ? _batchsize : listudfs.Count() - _startrange;
        List<ccProductUDFs> shallowlist = listudfs.GetRange(_startrange, sz);
        _startrange = _startrange + sz;

            _session = SessionContext.Session;
            // create a response list to hold results of uploads...
            List<ccResponse> response_categoryUDFs = new List<ccResponse>();

            // start the transaction
            using (var tx = _session.BeginTransaction())
            {
                _dbcontext.BeginTransaction();
                int counter = 0;
                int listcount = listudfs.Count();

                // loop through each remaining UDF
                // these are UDFs where the FIELD or the VALUE has changed, and we have not dealt with it as part of the product
                foreach (ccProductUDFs udf in shallowlist)
                {
                    if (ShowLog(verbose, (_startrange - sz) + ++counter, listcount))
                    {
                        TimeSpan elapsed = (DateTime.Now - started);
                        WriteLogV2("product udfs {0} of {1}", (_startrange - sz) + counter, listcount, elapsed);


                    }
                    // get the product for this UDF...
                    var product = _session.Query<Product>().FirstOrDefault(a => a.Sku == udf.SKU);


                    if (product != null)
                    {
                        // check that product has a product definition...
                        if (product.ProductDefinition == null)
                        {
                            // product has no definition assigned, so check that the product definition exists in data...
                            ProductDefinition definition = _session.Query<ProductDefinition>().FirstOrDefault(a => a.Description == udf.DefinitionName);
                            if (definition == null)
                            {
                                // product definition doesn;t exist in data, so create it...
                                definition = new ProductDefinition();
                                definition.Description = udf.DefinitionDescription;
                                definition.Name = udf.DefinitionName;

                                // save the changes...
                                _session.SaveOrUpdate((ProductDefinition)definition);


                            }

                            // assign this product definition to the product record...
                            product.ProductDefinition = definition;
                        }

                        // determine if the UDF FIELD exists...
                        ProductDefinitionField definitionfield = product.ProductDefinition.ProductDefinitionFields.FirstOrDefault(a => a.Name == udf.FieldName);
                        if (definitionfield == null)
                        {
                            // the UDF FIELD does NOT exist, so we shall add it.
                            definitionfield = new ProductDefinitionField();
                            definitionfield.Name = udf.FieldName;
                            definitionfield.ProductDefinition = product.ProductDefinition;

                            // locate the data type record and assign it to this UDF FIELD
                            var dt = _session.Query<DataType>().FirstOrDefault(a => a.TypeName == udf.DataType);
                            if (dt != null)
                            {
                                definitionfield.DataType = dt;
                            }

                            // add the UDF FIELD to the product category...
                            product.ProductDefinition.ProductDefinitionFields.Add(definitionfield);

                            // save the changes...
                            _session.SaveOrUpdate((Product)product);

                        }

                        bool changed = definitionfield.Deleted != udf.UdfFieldDeleted;

                        // assign properties to this UDF FIELD...
                        definitionfield.Deleted = udf.UdfFieldDeleted;

                        if (changed)
                        {
                            // save the changes...
                            _session.SaveOrUpdate((ProductDefinitionField)definitionfield);
                        }

                        // determine if the UDF VALUE record exists...
                        ProductProperty property = product.ProductProperties.FirstOrDefault(a => a.ProductDefinitionField.Name == definitionfield.Name && a.Product.Id == product.ProductId);
                        if (property == null)
                        {
                            // the UDF VALUE does NOT exist, so we shall add it.
                            property = new ProductProperty();
                            property.ProductDefinitionField = definitionfield;
                            property.Product = product;

                            // add the UDF VALUE to the product category...
                            product.ProductProperties.Add(property);
                        }

                        changed = false;

                        string v = udf.UdfValue == null ? string.Empty : udf.UdfValue.Trim();

                        changed = property.Value != v;

                        // assign properties to this UDF FIELD...
                        property.Value = v;

                        if (changed)
                        {
                            // save the changes...
                            _session.SaveOrUpdate((ProductProperty)property);

                            // save the changes...
                            _session.SaveOrUpdate((Product)product);
                        }

                        // update the response with a successful result...
                        response_categoryUDFs.Add(new ccResponse(udf.SKU, udf.FieldName, ccCategoryUDFsData.Source, true, "", 0));
                    }
                    object[] prodparam =
                                {
                                    _dbcontext.NewParameter("@Sku", udf.SKU),
                                    _dbcontext.NewParameter("@udfName", udf.FieldName)
                                };
                    _dbcontext.ExecuteNonQuery(CommandType.Text,
                        "UPDATE [LOAD_ProductUdfValues] SET HasChanged = 0 WHERE ProductId = @Sku And FieldName = @udfName",
                        prodparam);

                    TimeSpan ts = DateTime.Now - started;
                    doneCount++;
                    Console.WriteLine("Done {0} of {1} in {2}", doneCount, _totalCount, ts.ToString(@"hh\:mm\:ss"));
                }

                try
                {
                    // commit all changes...
                    tx.Commit();
                    _dbcontext.CommitTransaction();
                }
                catch (Exception ex)
                {
                    // Error Handler
                    tx.Rollback();
                    _dbcontext.RollbackTransaction();
                    response_categoryUDFs.Clear();
                    response_categoryUDFs.Add(new ccResponse("", "", ccCatalogData.Source, false, "Commit failed [" + ex.ToString() + "]", 1));
                }
            }

            // send any response...
            ccResponse.Write(_dbcontext, response_categoryUDFs, ccCatalogData.ResponseTarget);

            // tidy up the session before is it disposed...
            _session.Flush();
       // }
    }
    #endregion

1 个答案:

答案 0 :(得分:0)

如果有人在搜索中发现这一点,我已在_session.Clear();

之后添加_session.Flush();修复了我的问题