我正在使用Stream.generate
从Instagram获取数据。由于Instagram限制每小时的呼叫,我希望generate
每2秒运行频率更低。
我之所以选择这样的头衔,是因为我从ScheduledExecutorService.scheduleAtFixedRate
移开了,这就是我要搜索的内容。我确实意识到流中间操作是懒惰的,不能按计划调用。如果您对标题有更好的了解,请告诉我。
所以我希望在种族之间至少有2秒的延迟。
我的尝试没有考虑generate
之后的操作消耗的时间,这可能需要2秒以上的时间:
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;
})
答案 0 :(得分:4)
解决方案是将发生器与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);
如果数据处理时间超过2秒,则新数据将入队并等待消耗。如果它少于2秒,则生成器中的take
方法将等待调度程序生成新数据。
通过这种方式,您可以确保每小时向Instagram拨打少于N个电话!
答案 1 :(得分:2)
据我了解,你的问题是解决两个问题:
您可以使用基于截止日期的等待来解决第一项任务,第二项任务可以通过实施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 :(得分:1)
制作计时器和信号量。计时器每隔2秒就会提升一次信号量,并在流中等待每次调用信号量。
这使等待时间保持在指定的最小值(2秒),而且 - 有趣的是 - 甚至可以使用.parallel()
。
private final volatile Semaphore tickingSemaphore= new Semaphore(1, true);
在自己的主题中:
Stream.generate(() -> {
tickingSemaphore.acquire();
...
};
在计时器中:
tickingSemaphore.release();