多线程 - 线程池是不错的选择?

时间:2012-01-26 18:19:24

标签: c# multithreading threadpool

我有一个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)

4 个答案:

答案 0 :(得分:4)

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

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


编辑:

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

答案 1 :(得分:1)

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

答案 2 :(得分:1)

我认为这是一个不错的选择。但是,后台工作者已经被.Net 4 framworks tasks稍微取代了。这会根据您机器上的处理器数量进行优化,并根据相应的情况进行调整。也许您可以使用TPL并使用并行for。您可以传入要运行的最大并发线程池线程数,以便一次批量导入一次导入的文件数,例如:

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

This可能对您有帮助吗?

答案 3 :(得分:0)

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

要实现这一点,您将使用BlockingCollection(自.NET 4.0起)。文档中有一个例子。