我有一个多阶段管道。每个阶段都在一个单独的线程中运行,并使用有界的BlockingArrayQueues进行通信。我正在尝试多线程最慢的阶段以提高吞吐量。
问题:建议的实施方案是什么?是否有一个库可以使这个实现更简单&更容易阅读?
输入队列 - >阶段1(4个线程) - >有界队列 - >第二阶段
要求:
输入队列上的工作单位是独立的。
工作单位是严格排序的 - 输出应与输入的顺序相同。
必须限制第1阶段 - 如果输出超过特定大小,则必须停止。
阶段1中的异常应导致输出队列中的“毒丸”并终止ExecutorService。排队的任务应该尽力丢弃。
**我的建议实施:**
我正在考虑使用具有有限线程数的ThreadPoolExecutor。
将使用每个工作单元上的CountDown锁存器强制执行严格的排序。如果前一个工作单元的锁存器为0并且队列中有空间,则线程只能推送结果。这也会处理限制,因为线程将阻塞,直到输出队列上有空间。
class WorkUnit {
CountDownLatch previousLatch;
CountDownLatch myLatch;
}
class MyRunnable extends Runnable {
public void run() {
//do work...
previousLatch.await();
ouputQueue.put( result );
myLatch.countDown();
}
}
异常处理是我有点难过的地方。我想要压倒一切 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();
}
}
}
答案 0 :(得分:0)
使用ExecutorService需要完全异步设计,而不使用CountDownLatch.countDown()
或BlockingQueue.take()
等阻止操作。当某个操作B必须等待某些事件时,该事件应该通过向Runnable
提交ExecutorService
来启动操作B.
在这种情况下,您应该创建自定义类而不是队列。这些类应该接受消息并在内部存储它们,或者根据一些规则提交实现Stage1或Stage2的任务(例如,限制正在运行的Stage1任务的数量)。
关于订购,请用序列号替换对上一个任务的引用。