Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/314.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 并行循环、遍历大型XML文件会导致内存不足_C#_Parallel Processing - Fatal编程技术网

C# 并行循环、遍历大型XML文件会导致内存不足

C# 并行循环、遍历大型XML文件会导致内存不足,c#,parallel-processing,C#,Parallel Processing,我有一个需要解析的文件列表(大小可以在3KB到500MB之间) 为了更快,我想使用Parallel.ForEach指令来迭代我的文件列表 我知道我可以使用: Parallel.ForEach(files, new ParallelOptions { MaxDegreeOfParallelism = 2 }, file => { //Do stuff }); 以确保同时只处理两个文件。 但是,在两个文件为500MB+的情况下,我得到了一个内存不足异常。 你知道在C#中是否有一种方法

我有一个需要解析的文件列表(大小可以在3KB到500MB之间)

为了更快,我想使用Parallel.ForEach指令来迭代我的文件列表

我知道我可以使用:

Parallel.ForEach(files, new ParallelOptions { MaxDegreeOfParallelism = 2 }, file =>
{
    //Do stuff
});
以确保同时只处理两个文件。 但是,在两个文件为500MB+的情况下,我得到了一个内存不足异常。

你知道在C#中是否有一种方法可以使用布尔值来限制并行选项吗。 理想情况下,当处理的文件总大小低于1GB时,我希望处理尽可能多的文件(或者等到处理完文件)

我还考虑对文件列表进行排序(按大小),并在并行foreach循环中使用第一个文件和最后一个文件(假设总大小小于1GB)。但我还是不确定:

  • 如果可能的话
  • 语法是什么
  • 据我所知,Parallel.ForEach以给定的顺序遍历列表(在这种情况下,无法指定如何遍历列表…)

    如果您有任何建议,我们将不胜感激


    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++;
            }
        }
    }