简体   繁体   English

使用ExecutorService对管道模式中的阶段进行多线程处理

[英]Multi-threading a stage in the pipeline pattern with ExecutorService

I have a multi-stage pipeline. 我有一个多阶段的管道。 Each stage runs in a separate thread with communication happening using bounded BlockingArrayQueues. 每个阶段都在单独的线程中运行,并使用有限的BlockingArrayQueues进行通信。 I'm trying to multi-thread the slowest stage to improve throughput. 我正在尝试对最慢的阶段进行多线程处理以提高吞吐量。

Question: What is the recommended implementation for this? 问题:推荐的实现方法是什么? Is there a library that would make this implementation simpler & easier to read? 是否有一个库可使该实现更简单易读?

Input Queue -> Stage 1 (4 threads) -> Bounded Queue -> Stage 2 输入队列->阶段1(4个线程)->有界队列->阶段2

Requirements : 要求

  • Work units on the input queue are independent. 输入队列上的工作单元是独立的。

  • Work units are strictly ordered -- output should be in the same order as input. 工作单元是严格排序的-输出应与输入顺序相同。

  • Stage 1 must be throttled -- it must stop if the output exceeds a certain size. 必须对第1阶段进行调节-如果输出超过特定大小,则必须停止。

  • Exceptions in Stage 1 should result in a "poison pill" on the output queue and terminate the ExecutorService. 第1阶段的异常应导致输出队列上出现“毒药”并终止ExecutorService。 Queued tasks should be discarded best effort. 排队的任务应尽力而为。

** My proposed implementation:** **我建议的实施方式:**

I'm thinking of using a ThreadPoolExecutor with a limited # of threads. 我正在考虑使用线程数量有限的ThreadPoolExecutor。

Strict ordering will be enforced with a CountDown latch on each work unit. 严格的排序将通过每个工作单元上的CountDown锁来强制执行。 A thread can only push the result if the previous work unit's latch is 0 and there's space on the queue. 如果前一个工作单元的锁存器为0,并且队列中有空间,则线程只能推送结果。 This also takes care of throttling since the thread will block until there's room on the output queue. 由于线程将阻塞,直到输出队列中有空间,这也可以节流。

class WorkUnit {
   CountDownLatch previousLatch;
   CountDownLatch myLatch;
}

class MyRunnable extends Runnable {
   public void run() {
       //do work...
       previousLatch.await();
       ouputQueue.put( result );
       myLatch.countDown();
   }
}

Exception handling is where I'm a little stumped. 异常处理让我有些困惑。 I'm thinking of overriding ThreadPoolExecutor.afterExecute() which will call shutdownNow() if there's an exception. 我正在考虑重写ThreadPoolExecutor.afterExecute(),如果有异常,它将调用shutdownNow()。

class MyThreadPoolExecutor extends ThreadPoolExecutor {
      protected void afterExecute(Runnable r, Throwable t) {
           if(t != null) {
               //record exection, log, alert, etc
               ouput.put(POISON_PILL);
               shutdownNow();
           }
      }
}

Using ExecutorService requires totally asynchronous design, without using blocking operations like CountDownLatch.countDown() or BlockingQueue.take() . 使用ExecutorService需要完全异步的设计,而无需使用诸如CountDownLatch.countDown()BlockingQueue.take()类的阻塞操作。 When an action B must wait some event(s), then that event(s) should start action B by submiting a Runnable to the ExecutorService . 当动作B必须等待某些事件时,则该事件应通过将Runnable提交给ExecutorService来启动动作B。

In you case, you should create custom classes instead of the queues. 在这种情况下,您应该创建自定义类而不是队列。 That classes should accept messages and either store them internally, or submit tasks which implement Stage1 or Stage2, according to some rules (eg limit the number of running Stage1 tasks). 根据某些规则(例如,限制正在运行的Stage1任务的数量),这些类应该接受消息并将其存储在内部,或者提交实现Stage1或Stage2的任务。

As for ordering, replace reference to previous task with serial number. 至于订购,请用序列号替换对先前任务的引用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM