2017-12-18 252 views
0

我正在處理機器返回的數據。該機器通常用於大農場,它將採集不同深度的每個點的數據並使用不同的設備。與大量數據嵌套的foreach導致內存不足exe123

每場可容納70-100字段和每個字段包含約10萬條數據

在這裏,我需要處理每一個數據和應用基於客戶需求的一些計算。

我需要首先遍歷農場,然後農場下的字段,然後每個農場使用的設備然後根據深度記錄每個設備。所以最後我希望我做了大約10億次的迭代。 我的代碼看起來像下面

public async void MigrateData() 
     { 
      masterData = await CatalogService.ExportMasterData(AppDataModel.Catalog, this.UserId); 

      foreach (var fieldItem in masterData.Fields) 
      { 
       var fieldReferenceId = fieldItem.ReferenceId; 

       dynamic loggedData = AppDataModel.Documents.LoggedData.Where(data => data.FieldId == fieldReferenceId); 
       dynamic fieldDbMappingData = fieldItem; 

       foreach (var data in loggedData) 
       { 
        yieldMaster.OperationalLogModalResponse = await YieldDataMigrationService.AddOperationalLogs("loggedDataDescription"); 
        yieldMaster.OperationalLogDataModelResponse = await YieldDataMigrationService.AddOperationalLogData(fieldDbMappingData, yieldMaster.OperationalLogModalResponse); 

        FetchContentData(data); 

       } 

      } 

     } 
private async void FetchContentData(LoggedData data) 
     { 

      foreach (var opdata in data.OperationData) 
      { 
       var filteredList = AggregateDataBasedOnFilter(opdata); 

       int count = filteredList.Count; 
       totalRecordCount += count; 
       for (int i = 1; i <= count; i = i + 1000) 
       { 
        var response = await YieldDataMigrationService.AddYiledData(filteredList.GetRange(i, i + 1000 >= count ? count - i : 1000)); 

       } 
      } 
      //Filter data based on timestamp values , get the first data in 5 seconds interval 

      System.GC.Collect(); 
     } 

private dynamic AggregateDataBasedOnFilter(OperationData opdata) 
     { 
      List<dynamic> listSpacialRecords = new List<dynamic>(); 
      IEnumerable<SpatialRecord> spacialRecords = opdata.GetSpatialRecords(); 
      spacialRecords = GetAggregateBasedOnTimeStamb(spacialRecords); 
      Nullable<Guid> productid; 
      for (int depth = 0; depth <= opdata.MaxDepth; depth++) 
      { 
       IEnumerable<DeviceElementUse> deviceElementUses = opdata.GetDeviceElementUses(depth); 
       StevProduct productDbMappingData = masterData.Products.Where(product => product.ReferenceId == opdata.ProductId).FirstOrDefault(); 
       if (productDbMappingData == null) 
       { 
        productid = null; 
       } 
       else 
       { 
        productid = productDbMappingData.Id; 
       } 
       foreach (var deviceElement in deviceElementUses) 
       { 

        List<dynamic> dvList = new List<dynamic>(); 
        IEnumerable<WorkingData> workingData = deviceElement.GetWorkingDatas(); 

        //foreach (var spacerecord in spacialRecords) 
        Parallel.ForEach(spacialRecords, (spacerecord) => 
        { 
         List<MeterValue> dat = new List<MeterValue>(); 
         var latitude = ((AgGateway.ADAPT.ApplicationDataModel.Shapes.Point)spacerecord.Geometry).Y; 
         var longitude = ((AgGateway.ADAPT.ApplicationDataModel.Shapes.Point)spacerecord.Geometry).X; 
         var timeStamp = spacerecord.Timestamp; 
         //Parallel.ForEach(workingData, (wdItem) => 
         foreach (var wdItem in workingData) 
         { 
          RepresentationValue spaceMeteredValue = spacerecord.GetMeterValue(wdItem); 
          if (spaceMeteredValue != null && wdItem.Representation != null) 
          { 
           //row[wdItem.Representation.Code] = meteredValue.Value.Value; 
           var objMeterValue = new MeterValue(); 
           objMeterValue.key = wdItem.Representation.Code; 
           objMeterValue.value = spaceMeteredValue.Designator != null ? Convert.ToString(spaceMeteredValue.Designator) : ""; 
           dat.Add(objMeterValue); 
          } 
         } 
         var newSpacialvalue = new 
         { 
          operationLogDataId = yieldMaster.OperationalLogDataModelResponse.Id, 
          order = deviceElement.Order, 
          totalDistanceTravelled = deviceElement.TotalDistanceTravelled, 
          totalElapsedTime = deviceElement.TotalElapsedTime, 
          uploadedOn = DateTime.Now.ToUniversalTime(), 
          collectedOn = timeStamp.ToUniversalTime(), 
          cropId = "8296e610-c055-11e7-851e-ad7650a5f99c", 
          productId = productid, 
          latitude = latitude, 
          longitude = longitude, 
          deviceConfigurationId = deviceElement.DeviceConfigurationId, 
          operationDataId = deviceElement.OperationDataId, 
          spatialRecords = dat, 
          depth = depth, 
          timeStamp = timeStamp, 
          totaldata = totalRecordCount 
         }; 
         lock (listSpacialRecords) 
         { 
          listSpacialRecords.Add(newSpacialvalue); 
         } 

        }); 


       } 
      } 

      listSpacialRecords = listSpacialRecords 
        .Skip(1) 
        .Aggregate(
         listSpacialRecords.Take(1).ToList(), 
         (a, x) => 
         { 
          if (x.timeStamp.Subtract(a.Last().timeStamp).TotalSeconds >= 10.0) 
          { 
           a.Add(x); 
          } 
          return a; 
         }); 
      GC.Collect(); 
      return listSpacialRecords; 

     } 

我真實的情景比這更復雜。它有很多foreach和計算。整個過程運行超過30分鐘。但是在我之間我正在擺脫內存 的異常。不知道如何處理這麼龐大的數據。

任何人都有比嵌套的foreach更好的方法?或者避免內存不足的解決方案?

注意:我已將每個外觀都移動到單獨的功能中,但仍顯示內存不足錯誤。另外我有一個本地列表,它處理邏輯部分計算的數據。本地列表它不是全局對象

+0

跳過並處理批次? –

+0

你爲什麼要對'foreach(FieldData中的var字段)'進行三次**調用? – stuartd

+0

@stuartd對不起,這是一個錯字。編輯 –

回答

0

正如Puneet在評論中指出的那樣:「OutOfMemory沒有發生,因爲您正在遍歷一個較大的集合,但是因爲您可能會將該數據保存在臨時變量中,因爲這些變量可能不會足夠快地清理垃圾。我認爲你應該做一些明確的垃圾收集後的一些設置數量的檢查「

如果你不需要手動處置元素會更好。

{object}.Dispose(); 

或者把垃圾收集語句放在所有循環的末尾。

GC.Collect(); 

另外如果您的操作不是連續/積聚操作,您可以使用Parallel.Foreach以獲得更好的性能。

+0

我有GC.Collect();但仍然有問題 –

+0

@ArunprasanthKV然後你需要手動處理你創建的對象/緩存,只要不需要。 –

相關問題