【问题标题】:Java multi threading performance worst as increasing thread pool size随着线程池大小的增加,Java 多线程性能最差
【发布时间】:2016-12-19 09:06:50
【问题描述】:

我在 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);
    }

每个线程都在做以下事情

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

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

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

pagination code reference

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

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

No. of Threads   Execution Time(minutes)

   1                 16 
   3                 15
   8                 17
   10                17
   15                16
   20                12
   50                30

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

【问题讨论】:

  • 增加线程数不会自动提高性能,过多的线程会导致开销问题。很难说为什么你在 1 - 10 个线程上有相同的性能,也许你的瓶颈是数据库?是本地数据库吗?
  • 也可以是JVM配置,如果它运行在一个只能访问一个核心的隔离环境中,那么你也不会看到太大的改进。
  • 是的,它是本地数据库

标签: java multithreading mongodb processor cpu-cores


【解决方案1】:

由于您从单一来源读取输入数据,该部分很可能是 IO 绑定的(从您的应用程序的角度来看),因此并行执行它不会给您带来太多好处。相反-我认为在多个线程上并行执行类似的查询(只是分页不同)会对性能产生负面影响:必须在数据库上多次执行相同的工作,并且并行查询可能会相互影响方式。

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

  • 使用单个查询从数据库中获取数据
  • 拥有多个从结果集或中间队列获取数据项并处理它们的工作线程。无需固定批次,每个工人在完成前一个项目的处理后即可抓取下一个可用项目。

至于线程数:最短处理时间的“最佳位置”取决于处理类型。对于没有太多 IO 处理的 CPU 密集型任务,它很可能与可用内核的数量有关 - 在您的情况下为 2。

【讨论】:

    【解决方案2】:

    多线程不会随着线程数量的增加而提高性能。

    IO 绑定应用程序不会从多线程中获得太多收益。

    这取决于很多因素。参考这个相关的 SE 问题:

    Is multithreading faster than single thread?

    即使对于较少 IO 限制、CPU 密集型应用程序,也不要配置大量线程来提高性能。

    您可以将代码更改为:

    ExecutorService executor = Executors.newFixedThreadPool(
    Runtime.getRuntime().availableProcessors());
    

    或者(ForkJoinPool 如下 [从 jdk 1.8 版本开始工作)

    ExecutorService executor = Executors.newWorkStealingPool()
    

    ExecutorsAPI:

    public static ExecutorService newWorkStealingPool()
    

    使用所有可用处理器作为其目标并行级别创建一个工作窃取线程池

    【讨论】:

      猜你喜欢
      • 2012-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-04
      • 1970-01-01
      • 1970-01-01
      • 2017-04-26
      • 2014-11-22
      相关资源
      最近更新 更多