我在SQL Server中有一个表 dbo.Cache ,其中有两列:
我打算将大字符串存储在“值”列(> 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);
}
});
}
试图在每次读取数据库之前/之后执行GC.Collect(); GC.WaitForFullGCComplete();
-没有帮助
试图在较低级别上模仿这种行为,直接通过sqlDataReader.ExecuteReader(CommandBehavior.SequentialAccess)
读取数据-它抛出OutOfMemoryException
答案 0 :(得分:0)
因此,经过调查,我发现这只是一个OutOfMemory问题,因为在第8个并行请求分配30mb * 2(因为它是Unicode字符)之后,.Net在我的应用程序中分配的内存实际上超过了1.2GB,这足以满足我的工作站.net运行时开始因内存不足(https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals#ephemeral-generations-and-segments)而烦人。
话虽如此,我只能重试读取(内存分配)操作,直到成功迫使GC收集在catch块中为止。
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();
如果您对此有更好的解决方案,请告诉我