随着线程池大小的增加,Java多线程性能最差

omk*_*707 1 java multithreading processor cpu-cores mongodb

我在mongoDB中有4000万个数据.我正在从集合中并行读取数据,处理它并转储到另一个集合中.

作业初始化的示例代码.

ExecutorService executor = Executors.newFixedThreadPool(10);
int count = total_number_of_records in reading collection
int pageSize = 5000;
int counter = (int) ((count%pageSize==0)?(count/pageSize):(count/pageSize+1));
for (int i = 1; i <= counter; i++) {
        Runnable worker = new FinalParallelDataProcessingStrategyOperator(mongoDatabase,vendor,version,importDate,vendorId,i,securitiesId);
        executor.execute(worker);
    }
Run Code Online (Sandbox Code Playgroud)

每个线程都在做以下事情

public void run() {
    try {
        List<SecurityTemp> temps = loadDataInBatch();
        populateToNewCollection(temps);
        populateToAnotherCollection(temps);
    } catch (IOException e) {
        e.printStackTrace();
    }
}
Run Code Online (Sandbox Code Playgroud)

使用以下查询对加载数据进行分页

mongoDB.getCollection("reading_collection").find(whereClause).
            .skip(pagesize*(n-1)).limit(pagesize).batchSize(1000).iterator();
Run Code Online (Sandbox Code Playgroud)

分页代码参考

机器配置:2个CPU,每个1核

并行实现提供与顺序几乎相同的性能.数据子集的统计数据(319568条记录)

No. of Threads   Execution Time(minutes)

   1                 16 
   3                 15
   8                 17
   10                17
   15                16
   20                12
   50                30
Run Code Online (Sandbox Code Playgroud)

如何提高此应用程序的性能?

pie*_*t.t 5

由于您正在从单个源读取输入数据,该部分很可能是IO绑定的(从应用程序的角度来看),因此并行执行它不会获得太多收益.相反 - 我认为在多个线程上并行执行类似的查询(只是使用不同的分页)会产生负面的性能影响:在数据库上必须多次完成相同的工作,并且并行查询可能会相互进入办法.

另一个问题是,与读取输入相比,处理部分是否占用了大量时间.如果它不使用并行处理将无助于加快速度.如果是的话,我建议如下:

  • 使用单个查询从数据库中获取数据
  • 有多个工作线程从结果集或中间队列中获取数据项并处理它们.没有必要固定批次,每个工人只需完成处理前一个项目后就抓住下一个可用项目.

至于线程数:最小处理时间的"最佳位置"取决于处理的类型.对于没有太多IO处理的CPU密集型任务,它很可能是在可用内核的数量附近 - 在您的情况下2.