[英]OutOfMemoryException when updating a large list?
我的清單很大,如果需要,我想覆蓋一個值。 為此,我創建了列表的兩個子集,這似乎給了我一個OutOfMemoryException
。 這是我的代碼段:
if (ownRG != "")
{
List<string> maclist = ownRG.Split(',').ToList();
List<IVFile> temp = powlist.Where(a => maclist.Contains(a.Machine)).ToList();
powlist = powlist.Where(a => !maclist.Contains(a.Machine)).ToList(); // OOME Here
temp.ForEach(a => { a.ReportingGroup = ownRG; });
powlist.AddRange(temp);
}
本質上,我將列表分為需要更新的部分和不需要更新的部分,然后執行更新並將列表放回原處。 這工作得很好了小名單,但有一個打破OutOfMemoryException
中的第三行if
一個大名單。 我可以提高效率嗎?
注意
powlist
是大型列表(> 1m)。 maclist
只有1到10之間,但即使有1個項目也會中斷。
這是使用答案中的枚舉器代碼重新排列代碼的方法:
if (!string.IsNullOrEmpty(ownRG))
{
var maclist = new CommaSeparatedStringEnumerable(str);
var temp = powlist.Where(a => maclist.Contains(a.Machine));
foreach (var p in temp)
{
p.ReportingGroup = ownRG;
}
}
ToList
。 powlist
刪除temp
內容(無論如何您都在重新添加它們) 你可以遍歷列表中手動,而不是做你現在做什么,通過尋找,
人物和記住最后一次的位置發現了一個和之前的一個。 這肯定會使您的應用程序正常工作,因為這樣就無需立即將整個集合存儲在內存中。
代碼示例:
var str = "aaa,bbb,ccc";
var previousComma = -1;
var currentComma = 0;
for (; (currentComma = str.IndexOf(',', previousComma + 1)) != -1; previousComma = currentComma)
{
var currentItem = str.Substring(previousComma + 1, currentComma - previousComma - 1);
Console.WriteLine(currentItem);
}
var lastItem = str.Substring(previousComma + 1);
Console.WriteLine(lastItem);
如果您想以一種不錯的方式“正確”地進行操作,甚至可以編寫一個自定義枚舉器:
public class CommaSeparatedStringEnumerator : IEnumerator<string>
{
int previousComma = -1;
int currentComma = -1;
string bigString = null;
bool atEnd = false;
public CommaSeparatedStringEnumerator(string s)
{
if (s == null)
throw new ArgumentNullException("s");
bigString = s;
this.Reset();
}
public string Current { get; private set; }
public void Dispose() { /* No need to do anything here */ }
object IEnumerator.Current { get { return this.Current; } }
public bool MoveNext()
{
if (atEnd)
return false;
atEnd = (currentComma = bigString.IndexOf(',', previousComma + 1)) == -1;
if (!atEnd)
Current = bigString.Substring(previousComma + 1, currentComma - previousComma - 1);
else
Current = bigString.Substring(previousComma + 1);
previousComma = currentComma;
return true;
}
public void Reset()
{
previousComma = -1;
currentComma = -1;
atEnd = false;
this.Current = null;
}
}
public class CommaSeparatedStringEnumerable : IEnumerable<string>
{
string bigString = null;
public CommaSeparatedStringEnumerable(string s)
{
if (s == null)
throw new ArgumentNullException("s");
bigString = s;
}
public IEnumerator<string> GetEnumerator()
{
return new CommaSeparatedStringEnumerator(bigString);
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
然后,您可以像這樣迭代它:
var str = "aaa,bbb,ccc";
var enumerable = new CommaSeparatedStringEnumerable(str);
foreach (var item in enumerable)
{
Console.WriteLine(item);
}
我可以提高效率嗎?
是的你可以。 我建議使用更有效的數據格式(您可以根據需要瀏覽數據庫或XML,JSON等)。 如果您真的想使用逗號分隔的項目,請參見上面的代碼示例。
在循環中找到下一個','char。 取','和上一個','位置之間的子字符串。 在循環的末尾,保存對先前“,”位置(初始設置為0)的引用。 因此,您可以逐項解析項目,而不是一次解析所有項目。
無需從powlist
創建一堆子列表並將其重建。 只需遍歷powlist
並相應地更新ReportingGroup
屬性。
var maclist = new HashSet<string>( ownRG.Split(',') );
foreach( var item in powlist) {
if( maclist.Contains( item.Machine ) ){
item.ReportingGroup = ownRG;
}
}
由於這會更改powlist
,因此您不會分配任何額外的內存,也不會遇到OutOfMemoryException
。
您可以嘗試循環列表中的項目,但這會增加處理時間。
foreach(var item in powlist)
{
//do your opeartions
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.