多线程的PipeLine实现实例
来源:互联网 发布:usb转网络接口怎么驱动 编辑:程序博客网 时间:2024/05/21 07:59
多生产者多消费者的Blocking Queue
/** * A blocking queue which wraps {@code ArrayBlockingQueue}, and with the * following features. * <li>Use null object as end of queue. * <li>Supports muti-producers for the queue. Only if all the producers put a position-pill to * the queue, the queue will reach end of life. * * @param <T> * element type */public class Queue<T> { private ArrayBlockingQueue<Element<T>> queue = null; private AtomicInteger lifeValue ; private static int DEFAULT_LIFE_VALUE = 1; /** * * @param capacity The queue size * @param lifeValue It is set as the number of producer of the queue as a rule */ public Queue(int capacity, int lifeValue) { this.queue = new ArrayBlockingQueue<Element<T>>(capacity); this.lifeValue = new AtomicInteger(lifeValue); } public Queue(int capacity) { this( capacity, DEFAULT_LIFE_VALUE ); } /** * Put an position-pill to the queue. * @throws InterruptedException */ @SuppressWarnings("unchecked") public void putEnd() throws InterruptedException{ int life = this.lifeValue.decrementAndGet(); if(life <= 0 ){ this.queue.put(Element.NULL); } } /** * Put an element to the queue * @param element * @throws InterruptedException */ public void put(T element ) throws InterruptedException{ try { queue.put(new Element<T>(element)); } catch (InterruptedException e) { this.queue.clear(); throw e; } } /** * Take an element from the head of queue. * If queue is empty, the operation will be blocked. * * @return a non-nullable object if queue if not empty, or null if the queue is ended * @throws InterruptedException */ public T take() throws InterruptedException{ Element<T> element = this.queue.take(); if( Element.NULL == element){ this.queue.put(Element.NULL); } return element.getObject(); } /** * Take elements in batch from the queue. The operation will be blocked for a non-ended queue. * The fetched list size should be equal to count unless the queue is ended * @param count the desired element size to fetch * @return a List which contains the batch fetched element, or null if the queue is ended and empty * @throws InterruptedException */ public List<T> batchTake(int count) throws InterruptedException{ List<T> result = new ArrayList<T>(count); int size = 0; while(size < count){ T object = this.take(); if(object == null){ break; }else{ result.add(object); size ++; } } if(result.isEmpty()){ return null; } return result; } /** * Wrapper of object, which supports null * * @param <T> */ private static class Element<T> { @SuppressWarnings({"unchecked","rawtypes"}) static Element NULL = new Element(null); private T object; Element(T o) { this.object = o; } T getObject() { return this.object; } }}
PipeLine调度框架
/** * * An executor that uses multiple threads to run a job which involve muti-steps pipeline like source > intermediate steps > output. * * <li> Steps can be executed concurrently, and they communicates with each other by {@code Queue} * <li> A step can be executed with muti-thread concurrently, and the thread number can be configured * * @author yuliang * * @param <S> source type * @param <O> output type */@SuppressWarnings("rawtypes")public class ParallelPipeLineExecutor<S, O> { protected static final Logger LOGGER = Logger.getLogger(FourStepPiplineExecutor.class); private String pipeLineName; private ISource<S> source; private Queue<S> sourceQueue; private List<Queue> queues = new LinkedList<Queue>(); private List<PipeLineStep> processorSteps = new LinkedList<PipeLineStep>(); public ParallelPipeLineExecutor() { } public void setName(String pipeLineName) { this.pipeLineName = pipeLineName; } public void setSource(ISource<S> source, int sourceQueueSize) { this.source = source; this.sourceQueue = new Queue<S>(sourceQueueSize); } private String generateStepProcessorName(String stepName, int stepSequence){ return this.pipeLineName+"."+stepName+"#"+stepSequence; } private <T1, T2> void addNextStep(String name, ProcessorProvider<T1, T2> provider, int threadNum, int outQueueSize) { String stepName = (name == null) ? "Step" + (processorSteps.size()+1) : name; PipeLineStep step = new PipeLineStep(stepName, provider, threadNum); this.processorSteps.add(step); if (outQueueSize > 0) { Queue<T1> outQueue = new Queue<T1>(outQueueSize, threadNum); queues.add(outQueue); } } /** * Add next step for the pipeline * * @param provider * a {@code Processor} provider * @param threadNum * the thread number that run the step * @param outQueueSize * the size of queue where the step output to */ public <T1, T2> void addNextStep(ProcessorProvider<T1, T2> provider, int threadNum, int outQueueSize) { Preconditions.checkArgument(threadNum > 0, "threadNum: " + threadNum + "should be positive"); Preconditions.checkArgument(outQueueSize >= threadNum, "outQueueSize: " + outQueueSize + "should be greater than threadNum:" + threadNum); if (provider instanceof IdentityProcessor.Provider) { LOGGER.info("Skip a step because it use Indentity.Provider"); } else { this.addNextStep(null, provider, threadNum, outQueueSize); } } /** * Add sink step for the pipeline * * @param provider * provider a {@code Processor} provider * @param threadNum * the thread number that run the step */ public void addSinks(ProcessorProvider<O, Void> provider, int threadNum) { Preconditions.checkArgument(threadNum > 0, "threadNum: " + threadNum + "should be positive"); this.addNextStep("Output", provider, threadNum, 0); } /** * Launch the execution of the pipeline and wait until it is finished or exception occurs */ public void launchAndWait() { int workersCount = 0; final ExecutorService executorService = Executors.newCachedThreadPool(); ExecutorCompletionService<Worker> workerCompletionService = new ExecutorCompletionService<Worker>( executorService); try { //submit source worker Worker sourceWorker = new SourceWorker<S>(this.source, this.sourceQueue); sourceWorker.setName(this.generateStepProcessorName("sourceWorker", workersCount)); workerCompletionService.submit(sourceWorker); workersCount++; //submit processor workers including sink workers Queue inQueue = sourceQueue; Iterator<Queue> queuesIter = queues.iterator(); for (PipeLineStep step : processorSteps) { final Queue outQueue = queuesIter.hasNext() ? queuesIter.next() : null; int stepSequence = 0; for (IProcessor processor : step.generateProcessors()) { stepSequence ++; ProcessWorker worker = new ProcessWorker(inQueue, processor, outQueue); worker.setName(this.generateStepProcessorName(step.getName(), stepSequence)); workerCompletionService.submit(worker); workersCount++; } inQueue = outQueue; } //wait for completion or exception while (workersCount > 0) { Worker w = workerCompletionService.take().get(); if (w.getException() != null) { LOGGER.error(w + " finished with exception"); throw w.getException(); } else { LOGGER.info(workersCount + " finished "); } workersCount--; LOGGER.info(workersCount + " threads still running..."); } } catch (Exception e) { //Just throw exceptions so that job failure cause be be directly shown in DJS/HAM throw new RuntimeException(e); } finally { executorService.shutdown(); } } /** * A process step in the pipe line * */ private static class PipeLineStep { private String name; private ProcessorProvider processorProvider; private int concurrentThreadNum; public PipeLineStep(String name, ProcessorProvider provider, int threadNum) { this.name = name; this.processorProvider = provider; this.concurrentThreadNum = threadNum; } public String getName() { return name; } public List<IProcessor> generateProcessors() throws Exception { List<IProcessor> processors = new ArrayList<IProcessor>(); for (int i = 0; i < concurrentThreadNum; i++) { processors.add(processorProvider.get()); } return processors; } }}
Worker类
/** * A {@code Worker} which can pull inputs from {@code inQueue}, process inputs * and output the results to {@code outQueue} continuously * @author yuliang * * @param <I> process input type * @param <O> process output type */public class ProcessWorker<I, O> extends Worker { private Queue<I> inQueue; private IProcessor<I, O> processor; private Queue<O> outQueue; private int batchSize = 1; public ProcessWorker(Queue<I> inQueue, IProcessor<I, O> processor, Queue<O> outQueue) { super(); Preconditions.checkArgument(batchSize > 0, "batchSize should be greater than 0"); this.inQueue = inQueue; this.processor = processor; this.outQueue = outQueue; this.batchSize = processor.getBatchSize(); } @Override public void work() throws Exception { try { if (this.batchSize > 1 && this.processor.isBatchSupported()) { this.processByBatch(); } else { this.processOneByOne(); } } finally { if (outQueue != null) { outQueue.putEnd(); } } } /** * Fetch inputs from {@code inQueue}, and process inputs one by one and put * results to {@code outQueue} */ private void processOneByOne() throws Exception { while (true) { I in = inQueue.take(); if (in == null) { break; } O o = processor.process(in); if (o != null && outQueue != null) { outQueue.put(o); } } } /** * Fetch inputs from {@code inQueue}, and process inputs in batch and put * results to {@code outQueue} */ private void processByBatch() throws Exception { while (true) { List<I> in = inQueue.batchTake(this.batchSize); if (in == null) { break; } List<O> outs = processor.batchProcess(in); if (outs != null && outQueue != null) { for (O o : outs) { if (o != null) { outQueue.put(o); } } } } }}
/** * * A source worker is a {@code Worker} which produce source elements * @author yuliang * * @param <S> source element type */public class SourceWorker <S> extends Worker{ private Queue<S> outQueue; private ISource<S> source; public SourceWorker(ISource<S> source, Queue<S> sourceQueue) { super(); this.source = source; this.outQueue = sourceQueue; } @Override public void work() throws Exception { try{ while(true){ S o = source.nextSource(); if(o == null){ break; } this.outQueue.put(o); } }finally{ this.outQueue.putEnd(); } }}
- 多线程的PipeLine实现实例
- 多线程 Pipeline 的改进
- 多线程的 pipeline 设计模式
- LINUX多线程pipeline架构的创建分析
- Jedis源码解析(Pipeline的实现)
- jenkins的pipeline中实现git提交
- HDFS Ozone的Pipeline实现机制
- 用Gsoap实现多线程服务的实例
- c++中实现多线程的简单实例
- java多线程实现实例
- 持续集成利器-PIPELINE(二)-Multibranch Pipeline 实现feature branch的持续集成
- sparkmlib使用Pipeline实现简单的逻辑回归
- java swing实现的多线程实例代码教程-赛马demo
- 多线程编程在C++下实现的简单实例
- java swing实现的多线程实例代码教程-赛马demo
- gsoap服务端实现多线程实例
- 【多线程简单实例】CreateThread实现
- 【多线程简单实例】_beginthreadx实现
- 接口(interface)的简单示例
- 安卓eclipse工程导入叹号、出错
- ubuntu linux 批量删除文件
- Long Long、__int64使用总结
- 一些编程规范
- 多线程的PipeLine实现实例
- 桶式排序
- AsyncTask异步机制
- MQ for AIX安装与卸载
- LayoutInflater作用
- 判断二叉树是否包含另一棵二叉树或者树的子结构
- svn1.8 服务端 centos 安装
- TCP/IP详解学习笔记(8)-DNS域名系统 、TFTP及BOOTP
- HDU 1022 Train Problem I (栈)