我正在尝试使用cyclops-react来根据大小来批处理队列中的元素,但也要按时,这样当没有元素时它就不会阻塞
也许功能不是我的预期,或者我做错了什么
完整代码(Groovy)与生产者在另一个线程中是这样的:
Queue<String> queue = QueueFactories.<String>unboundedQueue().build();
new Thread({
while (true) {
sleep(1000)
queue.offer("New message " + System.currentTimeMillis());
}
}).start();
StreamSource.futureStream(queue, new LazyReact(ThreadPools.queueCopyExecutor))
.groupedBySizeAndTime(10,500,TimeUnit.MILLISECONDS)
.forEach({i->println(i + " Batch Time: ${System.currentTimeMillis()}")})
输出结果为:
[New message 1487673650332, Batch Time: 1487673651356]
[New message 1487673651348, New message 1487673652352, Batch Time: 1487673653356]
[New message 1487673653355, New message 1487673654357, Batch Time: 1487673655362]
[New message 1487673655362, New message 1487673656364, Batch Time: 1487673657365]
但是我期待每个批次中有一个元素,因为提供的元素之间的延迟是10秒,但批处理是每半秒
我也尝试使用异步流(Groovy代码):
Queue<String> queue = QueueFactories.<String>unboundedQueue().build();
StreamSource.futureStream(queue, new LazyReact(ThreadPools.queueCopyExecutor))
.async()
.groupedBySizeAndTime(10, 500,TimeUnit.MILLISECONDS)
.peek({i->println(i + "Batch Time: ${System.currentTimeMillis()}")}).run();
while (true) {
queue.offer("New message " + System.currentTimeMillis());
sleep(1000)
}
同样,它每2秒只进行一次批处理,有时每批等待两个元素,即使批处理中的超时是半秒:
[New message 1487673877780, Batch Time: 1487673878819]
[New message 1487673878811, New message 1487673879812, Batch Time: 1487673880815]
[New message 1487673880814, New message 1487673881819, Batch Time: 1487673882823]
[New message 1487673882823, New message 1487673883824, Batch Time: 1487673884828]
[New message 1487673884828, New message 1487673885831, Batch Time: 1487673886835]
我用非未来的非懒惰流进行了第三次实验,这次它起作用了。
Queue<String> queue = QueueFactories.<String>unboundedQueue().build();
new Thread({
while (true) {
sleep(1000)
queue.offer("New message " + System.currentTimeMillis());
}
}).start();
queue.stream()
.groupedBySizeAndTime(10,500,TimeUnit.MILLISECONDS)
.forEach({i->println(i + " Batch Time " + System.currentTimeMillis())})
结果:
[New message 1487673288017, New message 1487673289027, Batch Time , 1487673289055]
[New message 1487673290029, Batch Time , 1487673290029]
[New message 1487673291033, Batch Time , 1487673291033]
[New message 1487673292037, Batch Time , 1487673292037]
为什么在使用未来的流时,批处理的行为似乎是错误的?
答案 0 :(得分:0)
差异行为是由于一个错误降低了对async.Queue的FutureStreams进行分组的效率(基本上这意味着下一个结果出现在前一个500ms的限制内,而Stream会向队列询问另一个值和等到它到了)。这将在未来的cyclops-react版本中修复。
可以通过两种方式解决这个问题
在错误报告中使用Jesus Menendez建议的解决方法
queue.stream()
.groupedBySizeAndTime(batchSize, batchTimeoutMillis, TimeUnit.MILLISECONDS)
.futureStream(new LazyReact(ThreadPools.getSequential()))
.async()
.peek(this::executeBatch)
.run();
这可以避免导致两个值一起批处理的开销。
我们可以在500ms后超时(并且不要等到一个值到达队列中进行批处理),方法是使用streamBatch运算符
Queue<String> queue = QueueFactories.<String>unboundedQueue().build();
new Thread(()->{
for(int i=0;i<10;i++){
queue.offer("New message " + i);
sleep(10000);
}
queue.close();
}).start();
long toRun = TimeUnit.MILLISECONDS.toNanos(500l);
queue.streamBatch(new Subscription(), source->{
return ()->{
List<String> result = new ArrayList<>();
long start = System.nanoTime();
while (result.size() < 10 && (System.nanoTime() - start) < toRun) {
try {
String next = source.apply(1l, TimeUnit.MILLISECONDS);
if (next != null) {
result.add(next);
}
}catch(Queue.QueueTimeoutException e){
}
}
start=System.nanoTime();
return result;
};
}).filter(l->l.size()>0)
.futureStream(new LazyReact(ThreadPools.getSequential()))
.async()
.peek(System.out::println)
.run();
在这种情况下,我们将始终在500毫秒后分组,而不是等到我们要求的值到达队列。