顺序与并行解决方案内存使用情况
本文关键字:用情 情况 内存 解决方案 并行 顺序 | 更新日期: 2023-09-27 17:59:47
我对以下场景有一个小问题:我得到了一个ID值列表,我需要运行一个SELECT查询(其中ID是一个参数),然后将所有结果集组合为一个大的结果集,并将其返回给调用者。
由于每个ID的查询可能会运行几分钟(这是另一个问题,但目前我认为这是一个给定的事实),并且输入中可能有1000个ID,所以我尝试使用任务。通过这种方法,我体验到了内存使用的缓慢但坚实的增加。
作为测试,我也做了一个简单的顺序解决方案,它有正常的内存使用图,但正如预期的那样,速度非常慢。它在运行时会有所增加,但当它完成时,一切都会回落到正常水平。
以下是代码的骨架:
public class RowItem
{
public int ID { get; set; }
public string Name { get; set; }
//the rest of the properties
}
public List<RowItem> GetRowItems(List<int> customerIDs)
{
// this solution has the memory leak
var tasks = new List<Task<List<RowItem>>>();
foreach (var customerID in customerIDs)
{
var task = Task.Factory.StartNew(() => return ProcessCustomerID(customerID));
tasks.Add(task);
}
while (tasks.Any())
{
var index = Task.WaitAny(tasks.ToArray());
var task = tasks[index];
rowItems.AddRange(task.Result);
tasks.RemoveAt(index);
}
// this works fine, but slow
foreach (var customerID in customerIDs)
{
rowItems.AddRange(ProcessCustomerID(customerID)));
}
return rowItems;
}
private List<RowItem> ProcessCustomerID(int customerID)
{
var rowItems = new List<RowItem>();
using (var conn = new OracleConnection("XXX"))
{
conn.Open();
var sql = "SELECT * FROM ...";
using (var command = new OracleCommand(sql, conn))
{
using (var dataReader = command.ExecuteReader())
{
using (var dataTable = new DataTable())
{
dataTable.Load(dataReader);
rowItems = dataTable
.Rows
.OfType<DataRow>()
.Select(
row => new RowItem
{
ID = Convert.ToInt32(row["ID"]),
Name = row["Name"].ToString(),
//the rest of the properties
})
.ToList();
}
}
}
conn.Close();
}
return rowItems;
}
使用任务时我做错了什么?根据MSDN的这篇文章,我不需要手动处理它们,但几乎没有其他东西。我想ProcessCustomerID是可以的,因为它在两种变体中都被调用了。
更新为了记录当前的内存使用情况,我使用了Process.GetCurrentProcess().PrivateMemorySize64
,但我在任务管理器>>处理
使用实体框架,ProcessCustomerID方法可能看起来像:
List<RowItem> rowItems;
using(var ctx = new OracleEntities()){
rowItems = ctx.Customer
.Where(o => o.id == customerID)
.Select(
new RowItem
{
ID = Convert.ToInt32(row["ID"]),
Name = row["Name"].ToString(),
//the rest of the properties
}
).ToList();
}
return rowItems;
除非你正在传输大量数据,如图像、视频、数据或斑点,否则这应该是接近即时的,结果是1k数据。
如果不清楚什么需要时间,并且您使用10g之前的oracle,那么很难监控这一点。但是,如果您使用实体框架,您可以将监控附加到它上!http://www.hibernatingrhinos.com/products/efprof
至少一年前,Oracle支持实体框架5。
按照顺序,它们一个接一个地执行,并行地,它们实际上是在消耗资源和创建死锁的同时开始的。
我认为您没有任何证据表明并行执行中存在内存泄漏。
可能是垃圾收集发生在不同的时间,这就是为什么经历了两次不同的读数。你不能指望它能实时释放内存。只有在需要时才会进行网络垃圾收集。看看"垃圾收集基础"
任务管理器或Process.GetCurrentProcess().PrivateMemorySize64
可能不是找到内存泄漏的非常准确的方法。如果这样做,至少要确保调用完全垃圾回收,并在读取内存计数器之前等待挂起的终结器。
GC.Collect();
GC.WaitForPendingFinalizers();