C# 并行循环、遍历大型XML文件会导致内存不足
我有一个需要解析的文件列表(大小可以在3KB到500MB之间) 为了更快,我想使用Parallel.ForEach指令来迭代我的文件列表 我知道我可以使用:C# 并行循环、遍历大型XML文件会导致内存不足,c#,parallel-processing,C#,Parallel Processing,我有一个需要解析的文件列表(大小可以在3KB到500MB之间) 为了更快,我想使用Parallel.ForEach指令来迭代我的文件列表 我知道我可以使用: Parallel.ForEach(files, new ParallelOptions { MaxDegreeOfParallelism = 2 }, file => { //Do stuff }); 以确保同时只处理两个文件。 但是,在两个文件为500MB+的情况下,我得到了一个内存不足异常。 你知道在C#中是否有一种方法
Parallel.ForEach(files, new ParallelOptions { MaxDegreeOfParallelism = 2 }, file =>
{
//Do stuff
});
以确保同时只处理两个文件。
但是,在两个文件为500MB+的情况下,我得到了一个内存不足异常。
你知道在C#中是否有一种方法可以使用布尔值来限制并行选项吗。
理想情况下,当处理的文件总大小低于1GB时,我希望处理尽可能多的文件(或者等到处理完文件)
我还考虑对文件列表进行排序(按大小),并在并行foreach循环中使用第一个文件和最后一个文件(假设总大小小于1GB)。但我还是不确定:
Edit1: 以下是我如何读取文件的代码: 我需要从一个特定的节点开始读取:“RootElt”-这就是我不使用File.ReadAllText()的原因 NB:我最初使用的是XDocument,只需执行:doc.Load(),但这会导致内存不足异常(即使我逐个处理文件),而使用XmlReader解决方案的情况并非如此 读取后,我调用我的反序列化方法:
private T Deserialize<T>(string xml)
{
using (TextReader reader = new StringReader(xml))
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
var report = serializer.Deserialize(reader);
return (T)report;
}
}
private T反序列化(字符串xml)
{
使用(TextReader=new StringReader(xml))
{
XmlSerializer serializer=新的XmlSerializer(typeof(T));
var报告=序列化程序。反序列化(读取器);
返回(T)报告;
}
}
您可以使用以下多线程结构:
public class FileProcessor
{
private const long TotalSizeMax = 1073741824; // 1 GB
private static long _totalSizeCurrent;
public void ProcFiles(IList<FileInfo> fiList)
{
var totalFiles = fiList.Count;
var index = 0;
while (totalFiles > index)
{
var fi = fiList[index];
Monitor.Enter(_totalSizeCurrent);
var totalCandidate = _totalSizeCurrent + fi.Length;
if (totalCandidate > TotalSizeMax)
{
Monitor.Exit(_totalSizeCurrent);
Task.Delay(2000).Wait(); // delay 2 seconds
continue;
}
_totalSizeCurrent = totalCandidate;
Monitor.Exit(_totalSizeCurrent);
Task.Run(() =>
{
// Start parse FileInfo fi
//...
// End parse
Monitor.Enter(_totalSizeCurrent);
_totalSizeCurrent -= fi.Length;
Monitor.Exit(_totalSizeCurrent);
});
index++;
}
}
}
公共类文件处理器
{
private const long TotalSizeMax=1073741824;//1 GB
私有静态长_totalSizeCurrent;
公共作废程序文件(IList fiList)
{
var totalFiles=fiList.Count;
var指数=0;
while(totalFiles>索引)
{
var fi=菲利斯特[指数];
Monitor.Enter(_totalSizeCurrent);
var totalCandidate=_totalSizeCurrent+fi.Length;
如果(Total候选>TotalSizeMax)
{
监视器。退出(_totalSizeCurrent);
Task.Delay(2000).Wait();//延迟2秒
继续;
}
_totalSizeCurrent=totalCandidate;
监视器。退出(_totalSizeCurrent);
Task.Run(()=>
{
//开始解析文件信息
//...
//结束解析
Monitor.Enter(_totalSizeCurrent);
_totalSizeCurrent-=fi.长度;
监视器。退出(_totalSizeCurrent);
});
索引++;
}
}
}
您是如何解析文件的?我们需要一个。您在做什么导致内存不足异常?如果代码正在泄漏内存,则需要解决此问题。XmlReader
和XmlSerializer
类在误用时会泄漏内存。请与我们分享一些代码。您能确认您的应用程序是以64位运行的吗?当您创建XmlSerializer
时,它会为传入的类型创建一个缓存程序集(如果尚未创建)。如果在多线程环境中执行此操作,则很容易生成同一动态程序集的多个副本,这些副本不会被垃圾收集。我强烈怀疑这是内存泄漏的原因。只需在创建序列化程序的位置添加一个锁就足够了。这应该足以确保您不会创建动态序列化程序集的多个副本。然而,在我看来,I/O代码并不是真正可并行化的。我想这正是我所要求的。我通过只读取感兴趣的元素和标记(过滤内容而不是读取XML中的所有内容…)来绕过我的问题,我将在回答我的初始问题时批准该问题。非常感谢。
public class FileProcessor
{
private const long TotalSizeMax = 1073741824; // 1 GB
private static long _totalSizeCurrent;
public void ProcFiles(IList<FileInfo> fiList)
{
var totalFiles = fiList.Count;
var index = 0;
while (totalFiles > index)
{
var fi = fiList[index];
Monitor.Enter(_totalSizeCurrent);
var totalCandidate = _totalSizeCurrent + fi.Length;
if (totalCandidate > TotalSizeMax)
{
Monitor.Exit(_totalSizeCurrent);
Task.Delay(2000).Wait(); // delay 2 seconds
continue;
}
_totalSizeCurrent = totalCandidate;
Monitor.Exit(_totalSizeCurrent);
Task.Run(() =>
{
// Start parse FileInfo fi
//...
// End parse
Monitor.Enter(_totalSizeCurrent);
_totalSizeCurrent -= fi.Length;
Monitor.Exit(_totalSizeCurrent);
});
index++;
}
}
}