Spring Batch:带有AsyncItemProcessor的多线程步骤不会并行运行

时间:2019-09-08 08:34:36

标签: java spring spring-batch threadpoolexecutor itemprocessor

TL; DR

给出一个具有一百万记录的文件,其中文件的每一行都要执行大量的逻辑,这是读取文件并在每一行完成应用逻辑的最快方法。我对文件读取器使用了多线程步骤,该文件读取器的read方法为synchronized来读取文件,并且还使用了AsynItemProcessor以便在自己的线程中处理记录。

我的期望是AsynItemProcessor应该在从读者处获得记录后立即开始处理。每个记录应在其自己的线程中处理;但是,在我下面的示例中

似乎并非如此

我的Spring批处理作业中有一个步骤,该步骤使用具有20个线程和10000个提交间隔的TaskExecutor来读取文件。我还使用了AsycnItemProcessorAsyncItemWriter,因为数据处理的时间有时会比从文件中读取一行所需的时间更长。

<step id="aggregationStep">
    <tasklet throttle-limit="20" task-executor="taskExecutor">
        <chunk reader="fileReader"
            processor="asyncProcessor" writer="asyncWriter"
            commit-interval="10000" />
    </tasklet>
</step>

位置:

  1. fileReader是扩展FlatFileItemReader的类,而read方法是 synchronized ,并仅调用{ {1}}。
  2. super.read只是一个asyncProcessor bean,该bean从文件的每一行传递并按关键字进行分组,然后将其存储到容纳AsyncItemProcessor对象的单例bean中。换句话说,处理器只是将文件数据按几列进行分组,然后将此数据存储在内存中。
  3. Map<String,BigDecimal>只不过是一个asyncWriter,其中包含一个no操作AsyncItemWriter。换句话说,由于处理器本身正在进行聚合并将数据存储在内存中,因此该作业不需要进行任何类型的写入。 (ItemWriter
  4. 请注意,MapAsynItemProcessor上带有ThreadPoolTaskExecutorcorePoolSize=10,而maxPoolSize=20有自己的Step,带有{{ 1}}和ThreadPoolTaskExecutor

使用上面的设置,我的惊奇是读取和处理将并行进行。像这样:

  1. FileReader从文件中读取一条记录,并将其传递给处理器
  2. corePoolSize=20执行聚合。由于它是maxPoolSize=40,因此理想情况下,调用AsyncItemProcessor方法的线程应该可以自由地执行其他工作?
  3. 最后,AsyncItemProcessor将获得process并提取数据,但是由于委托是空操作AsynItemWriter,因此不执行任何操作。

但是当我添加一些日志时,我没有看到预期的结果:

Future

...打印更多这样的行,直到读取整个文件。只有在读取文件之后,我才开始看到处理器开始执行其工作:

ItemWriter

底线:为什么在文件已被完全读取之前处理器无法启动?无论用于2019-09-07 10:04:49 INFO FileReader:45 - Finished reading 2500 records 2019-09-07 10:04:49 INFO FileReader:45 - Finished reading 5000 records 2019-09-07 10:04:50 INFO FileReader:45 - Finished reading 7501 records 2019-09-07 10:04:50 INFO FileReader:45 - Finished reading 10000 records 2019-09-07 10:04:51 INFO FileReader:45 - Finished reading 12500 records 2019-09-07 10:04:51 INFO FileReader:45 - Finished reading 15000 records或整个2019-09-07 10:06:53 INFO FileProcessor:83 - Finished processing 2500 records 2019-09-07 10:08:28 INFO FileProcessor:83 - Finished processing 5000 records 2019-09-07 10:10:04 INFO FileProcessor:83 - Finished processing 7500 records 2019-09-07 10:11:40 INFO FileProcessor:83 - Finished processing 10000 records 2019-09-07 10:13:16 INFO FileProcessor:83 - Finished processing 12500 records 2019-09-07 10:14:51 INFO FileProcessor:83 - Finished processing 15000 records的{​​{1}}参数是什么,读取总是首先完成,然后才开始处理。

1 个答案:

答案 0 :(得分:0)

这是面向块的处理的工作方式。该步骤将读取变量中的X个项目(其中X是提交间隔),然后执行处理/写入。您可以在code of ChunkOrientedTasklet中看到它。

在多线程步骤中,每个块将由一个线程处理。