1

我已经实施了一种管道方法。我要遍历一棵树,我需要某些事先不可用的值......所以我必须并行(或之前)遍历树,并且对于我想要保存值的每个节点(descendantCount 例如)。

因此,我正在遍历树,然后从构造函数中调用一个方法,该方法调用通过 ExecutorService 启动的新线程。提交的 Callable 是:

    @Override
    public Void call() throws Exception {
        // Get descendants for every node and save it to a list.
        final ExecutorService executor =
            Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
        int index = 0;
        final Map<Integer, Diff> diffs = mDiffDatabase.getMap();
        final int depth = diffs.get(0).getDepth().getNewDepth();
        try {
            boolean first = true;
            for (final AbsAxis axis = new DescendantAxis(mNewRtx, true); index < diffs.size()
                && ((diffs.get(index).getDiff() == EDiff.DELETED && depth < diffs.get(index).getDepth()
                    .getOldDepth()) || axis.hasNext());) {
                if (axis.getTransaction().getNode().getKind() == ENodes.ROOT_KIND) {
                    axis.next();
                } else {
                    if (index < diffs.size() && diffs.get(index).getDiff() != EDiff.DELETED) {
                        axis.next();
                    }

                    final Future<Integer> submittedDescendants =
                        executor.submit(new Descendants(mNewRtx.getRevisionNumber(), mOldRtx
                            .getRevisionNumber(), axis.getTransaction().getNode().getNodeKey(), mDb
                            .getSession(), index, diffs));
                    final Future<Modification> submittedModifications =
                        executor.submit(new Modifications(mNewRtx.getRevisionNumber(), mOldRtx
                            .getRevisionNumber(), axis.getTransaction().getNode().getNodeKey(), mDb
                            .getSession(), index, diffs));
                    if (first) {
                        first = false;
                        mMaxDescendantCount = submittedDescendants.get();
                        // submittedModifications.get();
                    }
                    mDescendantsQueue.put(submittedDescendants);
                    mModificationQueue.put(submittedModifications);
                    index++;
                }
            }

            mNewRtx.close();
        } catch (final AbsTTException e) {
            LOGWRAPPER.error(e.getMessage(), e);
        }
        executor.shutdown();
        return null;
    }

因此,对于每个节点,它都会创建一个新的 Callable,它遍历每个节点的树并计算后代和修改(我实际上是将两个树修订融合在一起)。嗯,mDescendantsQueue 和 mModificationQueue 是 BlockingQueues。起初我只有descendantsQueue 并再次遍历树以获取每个节点的修改(计算在当前节点的子树中所做的修改)。然后我想为什么不并行执行并实现流水线方法。可悲的是,每次我实施另一个多线程“步骤”时,性能似乎都在下降。

也许是因为 XML 树通常不是那么深,并且并发开销太重:-/

起初我按顺序做所有事情,这是最快的: - 遍历树 - 每个节点遍历后代并计算 descendantCount 和 modifyCount

在对 BlockingQueues 使用流水线方法后,性能似乎有所下降,但我实际上没有进行任何时间测量,我必须恢复许多更改才能返回 :( 也许随着 CPU 的增加性能会提高,因为我只有一个Core2Duo 现在用于测试。

最好的问候,
约翰内斯

4

2 回答 2

1

可能这应该有所帮助:Amadahl 定律,它基本上说生产力的提高取决于(成反比)必须通过同步处理的代码的百分比。因此,即使通过增加更多的计算资源来增加,也不会得到更好的结果。理想情况下,如果(同步部分与总部分)的比率很低,那么使用(处理器数量 +1)应该提供最佳输出(除非您使用网络或其他 I/O,在这种情况下您可以增加大小池)。因此,只需从上面的链接跟进,看看是否有帮助

于 2011-09-09T14:49:00.013 回答
0

从您的描述看来,您正在递归地创建线程,每个线程都处理一个节点,然后产生一个新线程?这个对吗?如果是这样,我对您遭受性能下降并不感到惊讶。

一个简单的递归下降方法实际上可能是最好的方法。我看不出多线程在这里会给你带来什么好处。

于 2011-09-09T13:10:24.383 回答