[英]Stream generate at fixed rate
我正在使用Stream.generate
从Instagram获取数据。 由于instagram限制每小时的通话次数,因此我希望generate
通话频率要低于每2秒运行一次。
我之所以选择这样的标题,是因为我从ScheduledExecutorService.scheduleAtFixedRate
移走了,而这正是我要寻找的。 我确实意识到流中间操作是惰性的,无法按计划调用。 如果您对标题有更好的主意,请告诉我。
所以我再次希望各代之间至少有2秒的延迟。
我的尝试未考虑到generate
之后操作所耗费的时间,这可能需要花费比2s更长的时间:
Stream.generate(() -> {
List<MediaFeedData> feedDataList = null;
while (feedDataList == null) {
try {
Thread.sleep(2000);
feedDataList = newData();
} catch (InstagramException e) {
notifyError(e.getMessage());
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return feedDataList;
})
一种解决方案是将生成器与Stream
分离,例如使用BlockingQueue
final BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(100);
ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(1);
scheduler.scheduleAtFixedRate(() -> {
// Generate new data every 2s, regardless of their processing rate
ThreadLocalRandom random = ThreadLocalRandom.current();
queue.offer(random.nextInt(10));
}, 0, 2, TimeUnit.SECONDS);
Stream.generate(() -> {
try {
// Accept new data if ready, or wait for some more to be generated
return queue.take();
} catch (InterruptedException e) {}
return -1;
}).forEach(System.out::println);
如果数据处理时间超过2s,则新数据将入队并等待被使用。 如果花费的时间少于2秒,则生成器中的take
方法将等待调度程序生成新数据。
这样,您可以保证每小时打给Instagram的电话少于N次!
据我了解,您的问题是要解决两个问题:
您可以通过使用基于截止日期的等待来解决第一个任务,而通过实施Spliterator
可以解决第二个任务:
Stream<List<MediaFeedData>> stream = StreamSupport.stream(
new Spliterators.AbstractSpliterator<List<MediaFeedData>>(Long.MAX_VALUE, 0) {
long lastTime=System.currentTimeMillis();
@Override
public boolean tryAdvance(Consumer<? super List<MediaFeedData>> action) {
if(quitCondition()) return false;
List<MediaFeedData> feedDataList = null;
while (feedDataList == null) {
lastTime+=TimeUnit.SECONDS.toMillis(2);
while(System.currentTimeMillis()<lastTime)
LockSupport.parkUntil(lastTime);
try {
feedDataList=newData();
} catch (InstagramException e) {
notifyError(e.getMessage());
if(QUIT_ON_EXCEPTION) return false;
}
}
action.accept(feedDataList);
return true;
}
}, false);
制作一个计时器和一个信号灯。 计时器每2秒钟引发一次信号量,并且在流中,您每次都在等待该信号量。
这将等待时间保持在指定的最小值(2 s),并且有趣的是-甚至可以与.parallel()
。
private final volatile Semaphore tickingSemaphore= new Semaphore(1, true);
在其自己的线程中:
Stream.generate(() -> {
tickingSemaphore.acquire();
...
};
在计时器中:
tickingSemaphore.release();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.