2016-10-11 100 views
0

我有一個方法在涉及第三方API調用的記錄上運行,因此它不受CPU綁定並在後臺運行緩慢,但由於數據集太大,導致內存的問題。我無法一次加載整個列表(它會導致異常),因此我正在分批分頁。這可行,但每個批次都添加到內存使用情況,因爲我假設它正在被上下文跟蹤。爲長時間運行的IO綁定進程管理內存

我認爲要解決這個問題,我可以在完成處理後分離每批。我嘗試這樣做:

using (var db = new PlaceDBContext()) 
{ 
    int count = 0; 

    while(count < total) 
    { 
     var toCheck = db.Companies 
      .Include(x => x.CompaniesHouseRecords) 
      .Where(x => x.CheckedCompaniesHouse == false) 
      .OrderBy(x => x.ID) 
      .Skip(count) 
      .Take(1000) 
      .ToList(); 

     foreach (var company in toCheck) 
     { 
      // do all the stuff that needs to be done 
      // removed for brevity but it makes API calls 
      // and creates/updates records 

      company.CheckedCompaniesHouse = true; 
      db.SaveChanges(); 
      count++; 
     } 
     // attemmpted to detach to free up ram but doesn't work 
     db.Entry(toCheck).State = EntityState.Detached; 
    } 
} 

這導致該異常批次完成後:

的實體類型List`1是不是模型當前 背景

我的一部分猜測這是因爲我列舉它到一個列表,它實際上是跟蹤列表中的記錄。

什麼是正確的方式來分離記錄和嵌套的記錄,所以內存不填滿?我應該以不同的方式來解決這個問題嗎?

編輯:

我也試圖卸下每個公司的記錄,因爲我遍歷它,但RAM仍上升

 foreach (var company in toCheck) 
     { 
      // do all the stuff that needs to be done 
      // removed for brevity but it makes API calls 
      // and creates/updates records 

      company.CheckedCompaniesHouse = true; 
      db.SaveChanges(); 
      count++; 
      foreach(var chr in company.CompaniesHouseRecords.ToList()) 
      { 
       db.Entry(chr).State = EntityState.Detached; 
      } 
      db.Entry(company).State = EntityState.Detached; 
     } 
+0

'PlaceDBContext'是存儲實體跟蹤的地方,但我不確定它在什麼時候清除了緩存。有幾種不同的方法可以解決這個問題。一個簡單但很髒的方法是在while(count cost

回答

1

上下文意思是短暫的,廉價的創造,如果你」再擔心它佔用的內存和,因爲你同時是長期運行的,也許你可以試試這個這是一個問題:

int count = 0; 

while(count < total) 
{ 
    using (var db = new PlaceDBContext()) // create a new context each time 
    { 
     var toCheck = db.Companies 
      .Include(x => x.CompaniesHouseRecords) 
      .Where(x => x.CheckedCompaniesHouse == false) 
      .OrderBy(x => x.ID) 
      .Skip(count) 
      .Take(1000) 
      .ToList(); 

     foreach (var company in toCheck) 
     { 
      // do all the stuff that needs to be done 
      // removed for brevity but it makes API calls 
      // and creates/updates records 

      company.CheckedCompaniesHouse = true; 
      db.SaveChanges(); 
      count++; 
     } 
    } 
} 
+0

我剛剛試過這個,內存仍然上升到每批 – Guerrilla

+0

我做了一個更長時間的運行測試,並且GC似乎在很長一段時間內處理得更好,它在我做的更短的測試中正在增加。 – Guerrilla

+0

其實它仍然填滿。讓它在一夜之間運行,在5000條記錄超時後,VS在它的內存限制下 – Guerrilla

0

當你這樣做的負荷,在var toCheck = ...ü se .AsNoTracking()

在您的foreach循環中,保存每行的ID,然後使用第二個數據庫上下文加載這些公司,除非沒有包含大量額外鏈接對象的Include()。

然後做那些在循環更新,但問題只有一個db.SaveChanges()循環,否則你會做的每一行,這是1000一次一個分貝往返

using (var db = new PlaceDBContext()) 
{ 
    int count = 0; 

    while(count < total) 
    { 
     var toCheck = db.Companies 
      .AsNoTracking() 
      .Include(x => x.CompaniesHouseRecords) 
      .Where(x => x.CheckedCompaniesHouse == false) 
      .OrderBy(x => x.ID) 
      .Skip(count) 
      .Take(1000) 
      .ToList(); 

     foreach (var company in toCheck) 
     { 
      int tempID = company.ID // Use whatever field is the id 
      // do all the stuff that needs to be done 
      // removed for brevity but it makes API calls 
      // and creates/updates records 

      var companyUpdate = db2.Companies.Where(c => c.ID == tempid).FirstOrDefault();  

      companyUpdate.CheckedCompaniesHouse = true; 
      count++; 
     } 
     db2.SaveChanges(); 
    } 
} 
+0

這不起作用。即使我從ID創建公司記錄,內存仍然會增加。 – Guerrilla

相關問題