并行处理框架parseq调研

引入目的:为解决项目中存在的并且不好优化的n+1查询慢问题

使用时异步调用仅需一行 engine.run(e -> e.printStackTrace(), suppliers);

示例效果:

查询一组20个数据,每个子查询需要耗时1秒,返回结果并行组件需要1061ms,串行需要20057ms。并行处理的速度取决于任务数、线程数和子查询中最慢的那个。

package com.github.chenmingang.parseq;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;

public class OnlineSimulation {
    //    static EngineAgent engine = EngineFactory.defaultEngine();
    static EngineAgent engine = EngineFactory.getEngine(20, 1, 20);

    public static void main(String[] args) {
        long l1 = System.currentTimeMillis();
        List result1 = new OnlineSimulation().queryAsync();
        long l2 = System.currentTimeMillis();
        System.out.println("time1:" + (l2 - l1));
        //time1:1063

        long l3 = System.currentTimeMillis();
        List result2 = new OnlineSimulation().query();
        long l4 = System.currentTimeMillis();
        System.out.println("time2:" + (l4 - l3));
        //time2:20060

        engine.shutdown();
    }

    //n+1 查询
    public List query() {
        // 第一步查询
        List modelList = new ArrayList<>();
        for (int i = 1; i <= 20; i++) {
            modelList.add(new Model(i));
        }
        // 第二步查询
        for (Model model : modelList) {
            setName(model);
        }
        return modelList;
    }

    //n+1 查询
    public List queryAsync() {

        // 第一步查询
        List modelList = new ArrayList<>();
        for (int i = 1; i <= 20; i++) {
            modelList.add(new Model(i));
        }
        // 第二步查询
        List> suppliers = new ArrayList<>();
        for (Model model : modelList) {
            suppliers.add(() -> setName(model));
        }
        engine.run(e -> e.printStackTrace(), suppliers);

        return modelList;
    }

    /**
     * 执行子查询并合并数据的模拟
     *
     * @param model
     * @return
     */
    private Model setName(Model model) {
        model.setName("name-" + model.getId());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
        }
//        throw new RuntimeException("");
        return model;
    }

    class Model {
        private Integer id;
        private String name;

        public Model(Integer id) {
            this.id = id;
        }

        public Integer getId() {
            return id;
        }

        public void setId(Integer id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
}

根据这种列表式的查询场景对parseq做的封装

package com.github.chenmingang.parseq;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.linkedin.parseq.EngineBuilder;
import com.linkedin.parseq.batching.BatchingSupport;

import java.util.concurrent.*;

public class EngineFactory {

    private static EngineFactory INSTANCE = new EngineFactory();
    private final EngineAgent defaultEngine;

    private EngineFactory() {
        int numCores = Runtime.getRuntime().availableProcessors();
        defaultEngine = getEngine(numCores + 1, 1, numCores + 1);
    }

    public static EngineAgent defaultEngine() {
        return INSTANCE.defaultEngine;
    }

    public static EngineAgent getEngine(int poolSize, int scheduleSize, int queueNum) {
        ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(scheduleSize);
        ThreadFactory threadFactory = new ThreadFactoryBuilder().build();
        ThreadPoolExecutor executors = new ThreadPoolExecutor(poolSize, poolSize,
                0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(queueNum), threadFactory,
                (r, executor) -> {
                    try {
                        executor.getQueue().put(r);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                });

        final EngineBuilder builder = new EngineBuilder().setTaskExecutor(executors).setTimerScheduler(scheduler);
        final BatchingSupport batchingSupport = new BatchingSupport();

        builder.setPlanDeactivationListener(batchingSupport);
        return new EngineAgent(builder.build(), executors, scheduler);
    }

}
package com.github.chenmingang.parseq;

import com.linkedin.parseq.Engine;
import com.linkedin.parseq.Task;
import com.linkedin.parseq.promise.Promises;
import com.linkedin.parseq.promise.SettablePromise;

import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.function.Supplier;

public class EngineAgent {

    private Engine engine;
    private ThreadPoolExecutor executors;
    private ScheduledExecutorService scheduler;

    public EngineAgent(Engine engine, ThreadPoolExecutor executors,ScheduledExecutorService scheduler) {
        this.engine = engine;
        this.executors = executors;
        this.scheduler = scheduler;
    }
/**
     * 并行运行任务
     *
     * @param exceptionHandle 异常处理
     * @param suppliers       待执行的子任务
     * @param              每个子任务的返回结果
     * @return
     */
    public  List run(Consumer exceptionHandle, Supplier... suppliers) {
        List> list = new ArrayList<>();
        Collections.addAll(list, suppliers);
        return run(exceptionHandle, list);
    }

    /**
     * 并行运行任务
     *
     * @param exceptionHandle 异常处理
     * @param suppliers       待执行的子任务
     * @param              每个子任务的返回结果
     * @return
     */
    public  List run(Consumer exceptionHandle, List> suppliers) {
        if (suppliers == null || suppliers.size() == 0) {
            return null;
        }
        List> tasks = new ArrayList<>();
        for (Supplier supplier : suppliers) {
            Task task = this.task(supplier);
            tasks.add(task);
        }
        ParTask parTask = Tasks.par(tasks);
        engine.run(parTask);
        try {
            parTask.await();
            List successful = parTask.getSuccessful();
            Throwable error = parTask.getError();
            if (error != null && exceptionHandle != null) {
                exceptionHandle.accept(error);
            }
            return successful;
        } catch (InterruptedException e) {
            logger.error("中断异常", e);
        }
        return null;
    }

    public  SettablePromise async(Supplier supplier) {
        final SettablePromise promise = Promises.settable();
        getExecutors().execute(() -> {
            try {
                promise.done(supplier.get());
            } catch (Exception e) {
                promise.fail(e);
            }
        });
        return promise;
    }

    public  Task task(Supplier supplier) {
        return Task.async(() -> async(supplier));
    }

    public void run(final Task task) {
        engine.run(task);
    }

    public void shutdown() {
        engine.shutdown();
        executors.shutdown();
    }

    public ThreadPoolExecutor getExecutors() {
        return executors;
    }

    public ScheduledExecutorService getScheduler() {
        return scheduler;
    }
}

依赖版本

        
            com.linkedin.parseq
            parseq
            2.6.5
        
        
            com.linkedin.parseq
            parseq-batching
            2.6.5
        

你可能感兴趣的:(并行处理框架parseq调研)