c# - 使用任务计划程序的应用程序很快就会耗尽内存

标签 c# multithreading task-parallel-library task

应用程序解析某个目录中的文件,同时将新文件添加到目录中。我使用 ConcurrentQueue 并尝试将工作分配给核心数。因此,如果有文件要处理 - 它应该同时处理最多 4 个(核心)文件。 然而,在处理 10-30 个文件后,该应用程序会在几秒钟内运行 OOM。我看到内存消耗迅速增长到 ~1.5GB,然后出现 OOM 错误。 我是任务调度程序,所以我可能做错了什么。 文件解析是通过在文件上运行一些 .exe 来完成的,它使用 <5mb 或 ram。 任务调度程序在每次计时器线程结束时运行。但是它甚至在计时器第二次超时之前就运行了 OOM。

private void OnTimedEvent(object source, ElapsedEventArgs e)
    {
        DirectoryInfo info = new DirectoryInfo(AssemblyDirectory);
        FileInfo[] allSrcFiles = info.GetFiles("*.dat").OrderBy(p => p.CreationTime).ToArray();
        var validSrcFiles = allSrcFiles.Where(p => (DateTime.Now - p.CreationTime) > TimeSpan.FromSeconds(60));
        var newFilesToParse = validSrcFiles.Where(f => !ProcessedFiles.Contains(f.Name));
        if (newFilesToParse.Any()) Console.WriteLine("Adding " + newFilesToParse.Count() + " files to the Queue");
        foreach (var file in newFilesToParse)
        {
            FilesToParseQueue.Enqueue(file);
            ProcessedFiles.Add(file.Name);
        }
        if (!busy)
        {

            if (FilesToParseQueue.Any())
            {
                busy = true;
                Console.WriteLine("");
                Console.WriteLine("There are " + FilesToParseQueue.Count + " files in queue. Processing...");
            }
            var scheduler = new LimitedConcurrencyLevelTaskScheduler(coresCount); //4
            TaskFactory factory = new TaskFactory(scheduler);
            while (FilesToParseQueue.Any())
            {
                factory.StartNew(() =>
                {
                    FileInfo file;
                    if (FilesToParseQueue.TryDequeue(out file))
                    {
                        //Dequeue();
                        ParseFile(file);
                    }
                });
            }
            if (!FilesToParseQueue.Any())
            {
                busy = false;
                Console.WriteLine("Finished processing Files in the Queue. Waiting for new files...");
            }
        }
    }

最佳答案

只要有文件要处理,您的代码就会不断创建新的Task,而且它的速度要快得多,以至于可以处理文件。但它没有其他限制(如目录中的文件数),这就是它很快耗尽内存的原因。

一个简单的解决方法是将出列移到循环之外:

while (true)
{
    FileInfo file;
    if (FilesToParseQueue.TryDequeue(out file))
    {
        factory.StartNew(() => ParseFile(file));
    }
    else
    {
        break;
    }
}

如果您只为每个内核创建一个 Task 并在这些 Task 中使用循环处理文件,您将获得更好的性能。

关于c# - 使用任务计划程序的应用程序很快就会耗尽内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35352808/

相关文章:

linux - Linux 内核 v2.6+ 中的 pthread 与 kthread

java - thread.join() 从概念上讲是如何工作的?

c# - System.Threading.ThreadAbortException 在新线程中引发

c# - 为什么我的 ActionBlock 在我没有设置的情况下就处于已完成状态?

c# - 从 C# 使用 C++ 类

c# - WCF WSHttpBinding SOAP 安全协商失败

c# - NLog 不创建日志文件

c# - 在数据库上执行 "atomic"操作 "IncreaseIf"

Java 线程错误

c# - 我想等待抛出 AggregateException,而不仅仅是第一个异常