【发布时间】:2019-12-30 16:11:28
【问题描述】:
我有一个需要解析的文件列表(大小可以在 3KB 到 500MB 以上)。
为了更快地完成,我想使用 Parallel.ForEach 指令来迭代我的文件列表。
我知道我可以使用:
Parallel.ForEach(files, new ParallelOptions { MaxDegreeOfParallelism = 2 }, file =>
{
//Do stuff
});
为了确保同时只处理两个文件。 但是,在这两个文件超过 500MB 的情况下,我遇到了内存不足异常。
您知道 C# 中是否有一种方法可以使用布尔值来限制 ParallelOptions。 理想情况下,我希望在处理的文件总大小低于 1GB 时处理尽可能多的文件(或等到处理完的文件)
我还在考虑对我的文件列表进行排序(按大小),并在并行 foreach 循环中将第一个与最后一个放在一起(假设总大小低于 1GB)。但再一次,我不确定:
- 如果可能的话
- 语法是什么
据我了解,Parallel.ForEach 正在按照给定顺序遍历列表(在这种情况下,无法指定如何遍历我的列表...)
感谢您提供任何有关您将如何做的建议。
编辑1:
这是我如何读取文件的代码:
我需要从特定节点开始读取:“RootElt” - 这就是我不使用 File.ReadAllText() 的原因
using (XmlReader reader = XmlReader.Create(fi.FullName))
{
reader.ReadToDescendant("RootElt");
return reader.ReadOuterXml();
}
return string.Empty;
注意: 我最初使用 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;
}
}
【问题讨论】:
-
您是如何解析文件的?
-
我们需要minimal reproducible example。你在做什么会产生内存不足的异常?如果您的代码泄漏内存,则需要解决。
-
已知
XmlReader和XmlSerializer类在滥用时会泄漏内存。请与我们分享一些代码。您能否确认您的应用程序以 64 位运行? -
当您创建
XmlSerializer时,它会为传入的类型创建一个缓存程序集(如果还没有)。如果您在多线程环境中执行此操作,则很容易生成同一动态程序集的多个副本,这些副本不是垃圾收集。我强烈怀疑这是您的内存泄漏的根源。 -
在您创建序列化程序的地方简单地添加一个
lock可能就足够了。这应该足以确保您不会创建动态序列化程序集的多个副本。但是,在我看来,I/O 代码并不是真正可并行化的。 Task Parallel Library: Dataflow 你可能会做得更好