【问题标题】:List of Future-Instances未来实例列表
【发布时间】:2011-11-09 12:36:54
【问题描述】:

我想用更高效的东西替换未来实例列表。目前我正在遍历一棵树并提交一个 Callable 以确定树中每个节点的后代或自身节点的数量。我将 Future 实例保存在 List 中,然后在需要时从 List 中获取适当的节点数:

try {
    assert mIndex + 1 < mDescendants.size();
    mItem =
        Item.BUILDER.set(mAngle, mExtension, mIndexToParent).setParentDescendantCount(
                mParDescendantCount).setDescendantCount(mDescendants.get(mIndex + 1).get()).build();
} catch (final InterruptedException | ExecutionException e) {
    LOGWRAPPER.error(e.getMessage(), e);
}

可悲的是,使用 List 的轴必须等到所有 Future 实例都已提交。此外,它不会超出主内存限制:-/

也许 Google Guava 和 ListenableFuture 是正确的选择。

编辑:现在我想我实际上会使用 PropertyChangeListener 构建一些东西,每当触发 Future 时,Futures 就会添加到列表中。然后我将 CountDownLatch 初始化为 1 并在每次将新的 Future 添加到列表时调用 countDown() 。比如:

/**
 * {@inheritDoc}
 */
@Override
public boolean hasNext() {
    if (mDescendants.size() > 0) {
        return doHasNext();
    } else {
        try {
            mLatch.await(5, TimeUnit.SECONDS);
        } catch (final InterruptedException e) {
            LOGWRAPPER.error(e.getMessage(), e);
        }
        return doHasNext();
    }
}

然后在doHasNext()中:

try {
    assert mIndex + 1 < mDescendants.size();
    mItem =
        Item.BUILDER.set(mAngle, mExtension, mIndexToParent).setParentDescendantCount(
                mParDescendantCount).setDescendantCount(mDescendants.get(mIndex + 1).get()).build();
    mLatch = new CountDownLatch(1);
} catch (final InterruptedException | ExecutionException e) {
    LOGWRAPPER.error(e.getMessage(), e);
}

和监听器:

/** {@inheritDoc} */
@SuppressWarnings("unchecked")
@Override
public void propertyChange(final PropertyChangeEvent paramEvent) {
    Objects.requireNonNull(paramEvent);

    if ("descendants".equals(paramEvent.getPropertyName())) {
        mDescendants.add((Future<Integer>) paramEvent.getNewValue());
        mLatch.countDown();
    }
}

我不确定它是否有效,为时已晚,我不相信我会使用 CountDownLatch 的方式(尚未测试上述代码)。

编辑:以防万一有人感兴趣。我现在不再使用 CountDownLatch 和 List,而是简单地将 BlockingQueue 与 PropertyChangeListener 的实现结合使用,这似乎是一个很好的“干净”解决方案。

问候,

约翰内斯

【问题讨论】:

  • 我不太了解您提交的代码(Item.BUILDER 是做什么的?),但是,如果您的 List 太大而无法放入内存,一个可能的解决方案是重写您的代码改为使用迭代器/迭代器,并动态处理您的项目。 Guava 在 com.google.common.collect.Iterables 和 com.google.common.collect.Iterators 中有许多实用方法来帮助解决这个问题。
  • "feature instance" -> 你的意思是 Future 实例,对吧?

标签: java concurrency guava future executorservice


【解决方案1】:

您不能只使用completion service 吗?一旦提交,它将处理第一个未来完成...

【讨论】:

  • 不,我需要它们按顺序排列,这就是为什么我认为这是使用观察者模式和 BlockingQueue 的最佳方式。它只是一个管道或其他东西,它显然更快。现在我只需要替换另一个瓶颈,在所有项目都生产完毕后我会触发更改,这是浪费时间。
  • 如果您需要它们按特定顺序完成,它们不只是连续的吗?即,为什么不依次等待每个未来?影响与使用观察者相同吗?更简单..?我建议提交作业不应该是一个巨大的开销,它很可能会被等待每个作业完成所抵消。
  • 这似乎对较大的树产生了巨大的影响(尤其是 1MB 及以上——如果有人可能将其视为一棵较大的树)。它显然似乎扩展得更好,因为即使对于大约 2000 个节点,树的遍历和提交似乎也持续了大约 2 到 3 秒,但我还没有对其进行基准测试。由于这种流水线方法加快了整个过程:-)
  • 您的意思是提交调用需要 2 秒才能提交所需的对象构造/准备工作吗?
  • 不,通过树的整个迭代以及提交每个节点的可调用对象。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-02-07
  • 1970-01-01
  • 2017-05-16
  • 1970-01-01
  • 2023-01-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多