TL; DR
给出一个具有一百万记录的文件,其中文件的每一行都要执行大量的逻辑,这是读取文件并在每一行完成应用逻辑的最快方法。我对文件读取器使用了多线程步骤,该文件读取器的read
方法为synchronized
来读取文件,并且还使用了AsynItemProcessor
以便在自己的线程中处理记录。
我的期望是AsynItemProcessor
应该在从读者处获得记录后立即开始处理。每个记录应在其自己的线程中处理;但是,在我下面的示例中
我的Spring批处理作业中有一个步骤,该步骤使用具有20个线程和10000个提交间隔的TaskExecutor
来读取文件。我还使用了AsycnItemProcessor
和AsyncItemWriter
,因为数据处理的时间有时会比从文件中读取一行所需的时间更长。
<step id="aggregationStep">
<tasklet throttle-limit="20" task-executor="taskExecutor">
<chunk reader="fileReader"
processor="asyncProcessor" writer="asyncWriter"
commit-interval="10000" />
</tasklet>
</step>
位置:
fileReader
是扩展FlatFileItemReader
的类,而read
方法是 synchronized
,并仅调用{ {1}}。 super.read
只是一个asyncProcessor
bean,该bean从文件的每一行传递并按关键字进行分组,然后将其存储到容纳AsyncItemProcessor
对象的单例bean中。换句话说,处理器只是将文件数据按几列进行分组,然后将此数据存储在内存中。 Map<String,BigDecimal>
只不过是一个asyncWriter
,其中包含一个no操作AsyncItemWriter
。换句话说,由于处理器本身正在进行聚合并将数据存储在内存中,因此该作业不需要进行任何类型的写入。 (ItemWriter
。Map
在AsynItemProcessor
上带有ThreadPoolTaskExecutor
和corePoolSize=10
,而maxPoolSize=20
有自己的Step
,带有{{ 1}}和ThreadPoolTaskExecutor
使用上面的设置,我的惊奇是读取和处理将并行进行。像这样:
corePoolSize=20
执行聚合。由于它是maxPoolSize=40
,因此理想情况下,调用AsyncItemProcessor
方法的线程应该可以自由地执行其他工作?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}}参数是什么,读取总是首先完成,然后才开始处理。
答案 0 :(得分:0)
这是面向块的处理的工作方式。该步骤将读取变量中的X个项目(其中X是提交间隔),然后执行处理/写入。您可以在code of ChunkOrientedTasklet
中看到它。
在多线程步骤中,每个块将由一个线程处理。