繁体   English   中英

流以固定速率生成

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM