我有以下情形的輕微問題: 我給出的ID值的列表,我需要運行一個SELECT查詢(其中ID爲參數),然後將所有的結果集作爲一個大的結果集並將其返回給調用者。順序VS並行解決方案的內存使用情況
由於查詢可能每個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;
}
使用任務時,我在做什麼錯?根據this MSDN article,我不需要費心去處置它們,但幾乎沒有其他的東西。我猜想ProcessCustomerID是可以的,因爲它在兩種變體中都被調用。
更新 要記錄當前的內存使用情況我使用Process.GetCurrentProcess().PrivateMemorySize64
,但我注意到在任務管理器>>問題流程
我認爲你應該結合串行和並行的方法,通過限制任務的數量,內核在你的系統的數量,每個任務的處理順序一些IDS等於IdsCount/CoresCount(調整與分工餘!)。 – Graffito
我不認爲核心的限制會做任何事情;這些都是IO界限。這可能與Oracle驅動程序不會放棄內存有關。您不應該從列表中刪除任務或處理它們。 – Kit
@Szeki:你是如何測量內存使用量的? – CharithJ