【问题标题】:lambda foreach parallelStream creating less data than expectedlambda foreach parallelStream 创建的数据少于预期
【发布时间】:2019-01-29 10:30:37
【问题描述】:

我正在尝试实现一个 lambda foreach 数组列表的并行流,以提高现有应用程序的性能。

到目前为止,没有并行流的 foreach 迭代创建了写入数据库的预期数据量。

但是当我切换到parallelStream时,它总是向数据库写入更少的行。假设从预期的 10.000 行开始,将近 7000 行,但结果在这里有所不同。

知道我在这里缺少什么,数据竞争条件,还是我必须使用锁和同步?

代码基本上是这样的:

// Create Persons from an arraylist of data

arrayList.parallelStream()
          .filter(d -> d.personShouldBeCreated())
          .forEach(d -> {

   // Create a Person
   // Fill it's properties
   // Update object, what writes it into a DB

  }
);

到目前为止我尝试过的事情

使用...将结果收集到一个新列表中

collect(Collectors.toList())

...然后遍历新列表并执行逻辑,如第一个代码 sn-p 中所述。 新的“收集”ArrayList 的大小与预期结果匹配,但最终在数据库中创建的数据仍然较少

更新/解决方案:

根据我在该代码中标记的答案(以及 cmets 中的提示)关于非线程安全部分,我将其实现如下,最终给了我预期的数量数据。性能有所提高,现在只需要之前实现的 1/3。

StringBuffer sb = new StringBuffer();
arrayList()
  .parallelStream()
  .filter(d-> d.toBeCreated())
  .forEach(d ->
    sb.append(
            // Build an application specific XML for inserting or importing data
    )
  );

应用程序特定部分是一个基于 XML 的数据导入 api,但我认为这可以在普通的 SQL JDBC 插入中完成。

【问题讨论】:

  • 请提供personShouldBeCreated()实现
  • @Naya 在这里无关紧要...
  • @Eugene 不要这么认为,它可能包含一些线程不安全的代码。
  • 不要做你正在做的事情,而是看看批量插入。例如,将所有这些元素收集到 ArrayList 并一次性插入所有条目
  • 您正在使用非线程安全的数据结构,或者您的数据库接口对象不是线程安全的。能否添加相关代码(在forEach lambda 正文中所做的操作)?

标签: java lambda java-8 parallel-processing


【解决方案1】:

您的 lambda 代码很可能不是线程安全的,因为代码使用共享的非并发数据结构,或者它们的操作需要锁定

我怀疑批量/批量插入会比并行版本更快,并行版本可能会以庞大的短期连接结束,这些连接会在它们之间竞争锁定您正在插入的表。

也许您可以在并行编写大容量插入文件内容方面有所收获,但这取决于如何通过您的数据库 API 实现大容量插入...是否需要转储到文本文件中第一的?在这种情况下,您的并行流可以并行组成该文本的不同行,最后将它们加入文本文件以加载到数据库中。也许代替文本文件,它允许您在内存中使用语句对象的集合/列表,在这种情况下,您并行流可以并行创建这些对象并将它们收集到最终集合/列表中以批量插入到您的数据库中.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-27
    相关资源
    最近更新 更多