【问题标题】:Multithreading - Is threadpool good choice?多线程 - 线程池是不错的选择吗?
【发布时间】:2012-02-19 20:16:51
【问题描述】:

我有一个导入数千个文件的 c#(.Net 3.5) 应用程序。现在,我为每个文件创建后台工作者。它在一定限度内都能正常工作,然后应用程序因系统内存不足异常而死掉。我假设这是由于大量线程而发生的。对于这种情况,线程池是一个好的解决方案吗?

例外是:

    System.OutOfMemoryException | Exception of type 'System.OutOfMemoryException' was thrown. 
    at System.Data.RBTree`1.TreePage..ctor(Int32 size)
    at System.Data.RBTree`1.AllocPage(Int32 size)
    at System.Data.RBTree`1.InitTree()
    at System.Data.Index.InitRecords(IFilter filter)
    at System.Data.Index..ctor(DataTable table, Int32[] ndexDesc, IndexField[] indexFields,           
    Comparison`1 comparison, DataViewRowState recordStates, IFilter rowFilter)
    at System.Data.DataTable.GetIndex(IndexField[] indexDesc, DataViewRowState recordStates, IFilter 
    rowFilter)
    at System.Data.DataColumn.get_SortIndex()
    at System.Data.DataColumn.IsNotAllowDBNullViolated()
    at System.Data.DataTable.EnableConstraints()
    at System.Data.DataTable.set_EnforceConstraints(Boolean value)
    at System.Data.DataTable.EndLoadData()
    at System.Data.Common.DataAdapter.FillFromReader(DataSet dataset, DataTable datatable, String    
    srcTable, DataReaderContainer dataReader, Int32 startRecord, Int32 maxRecords, DataColumn    
    parentChapterColumn, Object parentChapterValue)
    at System.Data.Common.DataAdapter.Fill(DataTable[] dataTables, IDataReader dataReader, Int32 
    startRecord, Int32 maxRecords)
    at System.Data.Common.DbDataAdapter.FillInternal(DataSet dataset, DataTable[] datatables, Int32 
    startRecord, Int32 maxRecords, String srcTable, IDbCommand command, CommandBehavior behavior)
    at System.Data.Common.DbDataAdapter.Fill(DataTable[] dataTables, Int32 startRecord, Int32  
    maxRecords, IDbCommand command, CommandBehavior behavior)
    at System.Data.Common.DbDataAdapter.Fill(DataTable dataTable)
    at Dms.Data.Adapters.DataTableAdapterBase`2.FillByCommand(TTbl table, DbCommand command)

【问题讨论】:

  • 更新了问题。它在 c# 中。谢谢。
  • 如果您的应用程序是 32 位的并且您在内存中加载了超过 1.5 GB 的数据,您可能会遇到内存不足异常。有关更多信息,请参阅此问题:stackoverflow.com/questions/1109558/… 那么您是否一次加载超过 1.5 GB 的数据?
  • 您是将数千个文件中的数据导入应用程序的某个内部集合,还是将数据放入数据库或类似的东西中?
  • 我不知道您使用的是什么版本的 .net,但看看这个可能会有所帮助:codeproject.com/Articles/12551/…
  • 我正在导入文件并将它们放入数据库中。

标签: c# multithreading threadpool


【解决方案1】:

如果我的理解正确,您需要实施生产者-消费者方法: 1) 一个生产者 - 生产文件列表(要导入)。 2)几个(固定数量)消费者 - 执行导入。

要实现这一点,您可以使用BlockingCollection(从 .NET 4.0 开始)。文档中有一个示例。

【讨论】:

  • BlockingCollection 在 .net 4.0 中可用。我正在使用.net 3.5。但是如果我限制同时运行的后台工作的数量,会有帮助吗?
  • 没问题,请看这里的阻塞队列类实现:stackoverflow.com/questions/530211/…
【解决方案2】:

我认为这是一个不错的选择。但是,后台工作人员已被 .Net 4 框架tasks 所取代。这会根据您机器上的处理器数量进行优化,并相应地完成工作。也许您可以使用 TPL 并使用并行的for。您可以传入要运行的最大并发线程池线程数,以限制一次批量导入的文件数量,例如:

ParallelOptions options = new ParallelOptions();  
options.MaxDegreeOfParallelism = 4;

This 可以帮到你吗?

【讨论】:

    【解决方案3】:

    可以,是的。考虑只有有限数量的 CPU 或内核。只有那么多线程可以同时运行。你可以有更多的活动,比如说他们中的许多人是否会等待在另一台计算机上运行的其他进程(比如如果你正在下载这些文件)。仅仅因为你有一个单独的线程,并不意味着它增加了并发性。只是切换成本和内存分配(如您所见)。根据空闲时间的长短,尝试将您的池限制为比 CPU 稍多的线程。从那里进行调整。

    【讨论】:

    • 当我导入文件时,它认为它确实需要等待任何其他进程。用户输入列出所有文件及其位置的 txt 文件名,应用程序逐行解析此文件,每个文件都从指定位置读取并复制到应用程序数据库中。这是否澄清了我的情况?
    • 我的回答很笼统。我不知道您使用的是什么语言或框架。我对 C# 不熟悉。线程模型与语言无关,但正如其他响应者所表明的那样,很高兴“说”同一种语言来交流设计。也就是说,池化与管道可能没有太大区别。老板/工人正在有效地集中精力。无论哪种方式,您都通过有限的资源汇集了许多单独的任务。仍然笼统地说(就其价值而言),您可能会发现模型并不像它如何适合您的应用程序结构那么重要。
    【解决方案4】:

    问题很可能是您尝试一次加载太多文件。

    使用 ThreadPool 可能会有所帮助,因为它可以为您提供一种限制处理的方法。但是,如果您要导入和处理“数千个文件”,则适当的方法可能是创建一个管道来处理您的处理,然后用您的文件填充管道(或其中的一定数量)。这将使您可以控制并发量,并防止同时处理过多的单个文件。它可以将您的内存和处理要求保持在更合理的水平。


    编辑:

    既然您(现在)提到您正在使用 C#...BackgroundWorker 实际上确实使用了 ThreadPool。直接切换到使用线程池可能仍然是一个好主意,但它可能不会完全解决问题。您可能需要考虑使用 BlockingCollection<T> 之类的东西来设置生产者/消费者队列。然后,您可以让 1 个或多个线程“使用”文件并处理它们,然后将所有文件添加到 BlockingCollection<T>。这将使您能够控制一次处理多少个文件(只需添加另一个线程进行处理)。

    【讨论】:

    • +1 用于 BlockingCollection 建议。对用户来说是一个更明智的选择(如果他正确地描述了所有内容)
    猜你喜欢
    • 1970-01-01
    • 2010-10-04
    • 1970-01-01
    • 2013-10-22
    • 2010-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多