Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/visual-studio/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Spring批处理中多个输入文件的分区器多线程处理_Java_Multithreading_Spring_Spring Batch - Fatal编程技术网

Java Spring批处理中多个输入文件的分区器多线程处理

Java Spring批处理中多个输入文件的分区器多线程处理,java,multithreading,spring,spring-batch,Java,Multithreading,Spring,Spring Batch,我有一个包含超过1m个xml文件的文件夹和一个单线程步骤,该步骤以相同的方式处理这些xml文件中的每一个(没有与数据库的连接或文件之间的任何共同点)。有没有办法使这一步更加并行,例如使用一系列文件名进行分区,或者将文件拆分到不同的文件夹中,并使用文件夹的名称? 据我所知,我们不能像现在这样处理这种情况 为每个资源创建ExecutionContext,并将它们标记为{partition0,partition1,…,partitionN}。网格大小将被忽略 既然已经有了单独的文件,为什么需要分组以提


我有一个包含超过1m个xml文件的文件夹和一个单线程步骤,该步骤以相同的方式处理这些xml文件中的每一个(没有与数据库的连接或文件之间的任何共同点)。
有没有办法使这一步更加并行,例如使用一系列文件名进行分区,或者将文件拆分到不同的文件夹中,并使用文件夹的名称?

据我所知,我们不能像现在这样处理这种情况

为每个资源创建ExecutionContext,并将它们标记为{partition0,partition1,…,partitionN}。网格大小将被忽略


既然已经有了单独的文件,为什么需要分组以提高并发性。如果需要增加并发性,请增加线程数。在线程执行器中。假设您有1000个文件,并且有内存和cpu,您可以将max thread设置为50。因此,一次将处理50个文件。处理完文件后,将需要下一组50个文件。因此执行是并行的。这里有一个例子

<bean id="kpThreadPool"
    class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"
    destroy-method="destroy">
    <property name="maxPoolSize" value="${app.max_thread_num}" />
</bean>

<batch:step id="kp.step1" next="kp.step2">
        <batch:partition step="kp.slave"
            partitioner="multiResourcePartitioner">
            <batch:handler task-executor="kpThreadPool" />
        </batch:partition>
</batch:step>


其中app.max_thread_num=50

经过一些修补后,最好的结果来自一个自定义分区程序,该程序基于文件夹创建分区。为了实现这一点,上一步将每100k xml文件写入文件夹。
partitioner的代码(partitioner在如何管理步骤执行方面帮助很大):

公共类FolderPartitioner实现分区器{
私有静态最终记录器Logger=LoggerFactory.getLogger(FolderPartitioner.class);
私有静态最终字符串默认值\u KEY\u NAME=“fileName”;
私有静态最终字符串分区\u KEY=“PARTITION”;
私有字符串文件夹;
私有字符串keyName=默认密钥名称;
/**
*将每个分区映射到文件夹属性的子文件夹
*{@link ExecutionContext}。
* 
*/
公共地图分区(int gridSize){
Map Map=新的HashMap(
网格大小);
int i=0;
文件目录=新文件(文件夹);
File[]chunkList=dir.listFiles();
对于(文件chunkStep:chunkList){
if(chunkStep.isDirectory()){
ExecutionContext=新的ExecutionContext();
putString(keyName,chunkStep.getName());
info(“为文件夹创建分区:”+context.getString(keyName));
map.put(分区\键+i,上下文);
i++;
}
}
返回图;
}
/**
*每个{@link ExecutionContext}中文件名的键的名称。
*默认为“文件名”。
* 
*@param-keyName
*键的值
*/
public void setKeyName(字符串keyName){
this.keyName=keyName;
}
公共字符串getFolder(){
返回文件夹;
}
/**
*包含用于将子文件夹拆分为步骤的子文件夹的文件夹的名称
* 
*@param文件夹
*/
公用void文件夹(字符串文件夹){
this.folder=文件夹;
}
}


使用此分区器,执行时间从2小时变为40分钟(!!)。

您的回答确实帮助我理解了对庞大的XML文件夹进行分组的必要性(+1),结果是一个自定义分区器,它为每个文件夹创建分区
public class FolderPartitioner implements Partitioner {

    private static final Logger logger = LoggerFactory.getLogger(FolderPartitioner.class);

    private static final String DEFAULT_KEY_NAME = "fileName";

    private static final String PARTITION_KEY = "partition";

    private String folder;

    private String keyName = DEFAULT_KEY_NAME;

    /**
     * Map each partition to a subfolder of the folder property
     * {@link ExecutionContext}.
     * 
     */
    public Map<String, ExecutionContext> partition(int gridSize) {
        Map<String, ExecutionContext> map = new HashMap<String, ExecutionContext>(
                gridSize);
        int i = 0;
        File dir = new File(folder);
        File[] chunkList = dir.listFiles();
        for (File chunkStep : chunkList) {
            if (chunkStep.isDirectory()) {

                ExecutionContext context = new ExecutionContext();
                context.putString(keyName, chunkStep.getName());
                logger.info("Creating partition for folder:" + context.getString(keyName));
                map.put(PARTITION_KEY + i, context);
                i++;
            }
        }
        return map;
    }

    /**
     * The name of the key for the file name in each {@link ExecutionContext}.
     * Defaults to "fileName".
     * 
     * @param keyName
     *            the value of the key
     */
    public void setKeyName(String keyName) {
        this.keyName = keyName;
    }

    public String getFolder() {
        return folder;
    }

    /**
     * The name of the folder which contains the subfolders for spliting them to steps
     * 
     * @param folder
     */
    public void setFolder(String folder) {
        this.folder = folder;
    }

}