EF Core-关闭读者(OutofMemory)时尝试调用CheckDataisReady



我在sql server中有一个表 dbo.cache ,带有两个列:

  • 键:varchar(50)
  • 值:nvarchar(max)

我打算将大字符串存储在价值列(> 30MB)中,并在多个线程中查询它们。

这样的问题是,当我在并行进行9个查询时进行更多查询时,它开始抛出异常System.InvalidOperationException : Invalid attempt to call CheckDataIsReady when reader is closed

[Fact]
public void TestMemory()
{
    const string key = "myKey1";
    //re-creating record with Value = large 30mb string
    using (var db = new MyDbContext())
    {
        var existingRecord = db.CachedValues.FirstOrDefault(e => e.Key == key);
        if (existingRecord!=null)
        {
            db.Remove(existingRecord);
            db.SaveChanges();
        }
        var myHugeString = new string('*',30*1024*1024);
        db.CachedValues.Add(new CachedValue() {Key = key, Value = myHugeString});
        db.SaveChanges();
    }
    //Try to load this record in parallel threads, creating new dbContext
    const int threads = 10;
    Parallel.For(1, threads, new ParallelOptions(){MaxDegreeOfParallelism = threads}, (i) =>
    {
        using (var db = new MyDbContext())
        {
            var entity = db.CachedValues.FirstOrDefault(c => c.Key == key);
        }
    });
}

试图在每次读取DB之前/之后执行GC.Collect(); GC.WaitForFullGCComplete(); - 不帮助

试图通过sqlDataReader.ExecuteReader(CommandBehavior.SequentialAccess)直接在较低层次上模仿这种行为 - 它抛出OutOfMemoryException

因此,在调查后,我发现这只是一个淘汰问题的问题,因为在分配30mb*2的第8个并联请求后(因为它是Unicode char),由.NET分配的内存数量实际上超过1.2GB在我的应用程序中,对于我的Workstation .NET运行时间就足够了,可以在缺乏记忆的情况下开始锁定(https://learn.microsoft.com/en-us/dotnet/dant/standard/standard/garbage-collection/garbage-collection/fundamentals#ephemeral-generations-and-generations-and-and-and-and-an--generations-and-an--generation - 段)。

这样说,我没有其他东西只是在重试读取(MEM分配)操作之前,直到它成功地强迫GC收集在捕获块中。

Retry.Action(() =>
{
    using (var db = new MyDbContext())
    {
        var entity = db.CachedValues.FirstOrDefault(c => c.Key == key);
    }
}).OnException((OutOfMemoryException exception) =>
{
    GC.Collect();
    GC.WaitForFullGCComplete();
    return true;
})
.OnException((InvalidOperationException exception) =>
{
    if (exception.Message != "Invalid attempt to call CheckDataIsReady when reader is closed.")
    {
        return false;
    }
    GC.Collect();
    GC.WaitForFullGCComplete();
    return true;
})
.Run();

如果您知道一些更好的解决方案

,请告诉我

相关内容

  • 没有找到相关文章

最新更新