管理长时间运行的IO绑定进程的内存

时间:2016-10-11 01:03:58

标签: c# .net entity-framework

我有一个在涉及第三方API调用的记录上运行的方法,因此它不受CPU限制并在后台运行缓慢,但由于数据集太大而导致内存问题。我不能一次加载整个列表(它会导致异常)所以我正在批量分页。这是有效的,但每个批次都添加到ram用法,因为我假设它正被上下文跟踪。

我认为要解决这个问题,我可以在完成处理后分离每批。我试过这个:

{Binding Source={StaticResource lower1_1}, Converter={ ..... –

批处理完成后会导致此异常:

  

实体类型List`1不是当前模型的一部分   上下文

我想这是因为我将它枚举到一个列表中,它实际上是跟踪列表中的记录。

分离记录和嵌套记录以使ram不填满的正确方法是什么?我应该以不同的方式接近这个吗?

编辑:

我还尝试分离每个公司的记录,因为我循环它但是ram仍然上升

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;
    }
}

2 个答案:

答案 0 :(得分: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++;
        }
    }
}

答案 1 :(得分:0)

当您执行加载时,请var toCheck = ...使用.AsNoTracking()

foreach循环中,保存每行的ID,然后使用第二个db上下文来加载这些公司,除非没有包含大量额外链接对象的Include()。

然后对循环中的那些进行更新,但在循环之后只发出一个db.SaveChanges(),否则你将为每一行进行db往返,即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();  
    }
}