在另一个(可能是懒惰的)seq上创建一个排队的seq。排队 seq将在后台生成一个具体的seq,并且可以起床 消费者面前的物品。 n或q可以是整数n缓冲区 size或java.util.concurrent BlockingQueue的实例。注意 如果读者超前,那么从一个序列中读取就会阻止 生产者。
http://clojure.github.com/clojure/clojure.core-api.html#clojure.core/seque
我到目前为止的尝试+一些测试:https://gist.github.com/934781
Java或Clojure的解决方案表示赞赏。
答案 0 :(得分:0)
class Reader {
private final ExecutorService ex = Executors.newSingleThreadExecutor();
private final List<Object> completed = new ArrayList<Object>();
private final BlockingQueue<Object> doneQueue = new LinkedBlockingQueue<Object>();
private int pending = 0;
public synchronized Object take() {
removeDone();
queue();
Object rVal;
if(completed.isEmpty()) {
try {
rVal = doneQueue.take();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
pending--;
} else {
rVal = completed.remove(0);
}
queue();
return rVal;
}
private void removeDone() {
Object current = doneQueue.poll();
while(current != null) {
completed.add(current);
pending--;
current = doneQueue.poll();
}
}
private void queue() {
while(pending < 10) {
pending++;
ex.submit(new Runnable() {
@Override
public void run() {
doneQueue.add(compute());
}
private Object compute() {
//do actual computation here
return new Object();
}
});
}
}
}
答案 1 :(得分:0)
不是我害怕的答案,而是一些言论和更多问题。我的第一个答案是:使用clojure.core/seque
。生产者需要以某种方式告知消费者,以便知道何时停止,并且我假设生产元素的数量事先不知道。为什么你不能使用EOS标记(如果你的意思是队列中毒)?
如果我正确理解了您的替代seque
实现,那么当元素从您的函数外部移出时,它将会中断,因为channel
和q
在这种情况下将失去一步:频道将包含比#(.take q)
中的元素更多的q
个元素,导致它被阻止。可能有一些方法可以确保channel
和q
始终处于同步状态,但这可能需要实现您自己的Queue
类,并且它增加了太多的复杂性,我怀疑它是值得的。
此外,您的实现不区分正常的EOS和由于线程中断导致的异常队列终止 - 取决于您使用它的原因,您可能想知道哪个是哪个。就个人而言,我不喜欢以这种方式使用异常 - 在异常情况下使用异常,而不是正常的流控制。